sequel 3.37.0 → 3.38.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +56 -0
- data/README.rdoc +82 -58
- data/Rakefile +6 -5
- data/bin/sequel +1 -1
- data/doc/active_record.rdoc +67 -52
- data/doc/advanced_associations.rdoc +33 -48
- data/doc/association_basics.rdoc +41 -51
- data/doc/cheat_sheet.rdoc +21 -21
- data/doc/core_extensions.rdoc +374 -0
- data/doc/dataset_basics.rdoc +5 -5
- data/doc/dataset_filtering.rdoc +47 -43
- data/doc/mass_assignment.rdoc +1 -1
- data/doc/migration.rdoc +4 -5
- data/doc/model_hooks.rdoc +3 -3
- data/doc/object_model.rdoc +31 -25
- data/doc/opening_databases.rdoc +19 -5
- data/doc/prepared_statements.rdoc +2 -2
- data/doc/querying.rdoc +109 -52
- data/doc/reflection.rdoc +6 -6
- data/doc/release_notes/3.38.0.txt +234 -0
- data/doc/schema_modification.rdoc +22 -13
- data/doc/sharding.rdoc +8 -9
- data/doc/sql.rdoc +154 -112
- data/doc/testing.rdoc +47 -7
- data/doc/thread_safety.rdoc +1 -1
- data/doc/transactions.rdoc +1 -1
- data/doc/validations.rdoc +1 -1
- data/doc/virtual_rows.rdoc +29 -43
- data/lib/sequel/adapters/do/postgres.rb +1 -4
- data/lib/sequel/adapters/jdbc.rb +14 -3
- data/lib/sequel/adapters/jdbc/db2.rb +9 -0
- data/lib/sequel/adapters/jdbc/derby.rb +41 -4
- data/lib/sequel/adapters/jdbc/jtds.rb +11 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +3 -6
- data/lib/sequel/adapters/mock.rb +10 -4
- data/lib/sequel/adapters/postgres.rb +1 -28
- data/lib/sequel/adapters/shared/mssql.rb +23 -13
- data/lib/sequel/adapters/shared/postgres.rb +46 -0
- data/lib/sequel/adapters/swift.rb +21 -13
- data/lib/sequel/adapters/swift/mysql.rb +1 -0
- data/lib/sequel/adapters/swift/postgres.rb +4 -5
- data/lib/sequel/adapters/swift/sqlite.rb +2 -1
- data/lib/sequel/adapters/tinytds.rb +14 -2
- data/lib/sequel/adapters/utils/pg_types.rb +5 -0
- data/lib/sequel/core.rb +29 -17
- data/lib/sequel/database/query.rb +1 -1
- data/lib/sequel/database/schema_generator.rb +3 -0
- data/lib/sequel/dataset/actions.rb +5 -6
- data/lib/sequel/dataset/query.rb +7 -7
- data/lib/sequel/dataset/sql.rb +5 -18
- data/lib/sequel/extensions/core_extensions.rb +8 -12
- data/lib/sequel/extensions/pg_array.rb +59 -33
- data/lib/sequel/extensions/pg_array_ops.rb +32 -4
- data/lib/sequel/extensions/pg_auto_parameterize.rb +1 -1
- data/lib/sequel/extensions/pg_hstore.rb +32 -17
- data/lib/sequel/extensions/pg_hstore_ops.rb +32 -3
- data/lib/sequel/extensions/pg_inet.rb +1 -2
- data/lib/sequel/extensions/pg_interval.rb +0 -1
- data/lib/sequel/extensions/pg_json.rb +41 -23
- data/lib/sequel/extensions/pg_range.rb +36 -11
- data/lib/sequel/extensions/pg_range_ops.rb +32 -4
- data/lib/sequel/extensions/pg_row.rb +572 -0
- data/lib/sequel/extensions/pg_row_ops.rb +164 -0
- data/lib/sequel/extensions/query.rb +3 -3
- data/lib/sequel/extensions/schema_dumper.rb +7 -8
- data/lib/sequel/extensions/select_remove.rb +1 -1
- data/lib/sequel/model/base.rb +1 -0
- data/lib/sequel/no_core_ext.rb +1 -1
- data/lib/sequel/plugins/pg_row.rb +121 -0
- data/lib/sequel/plugins/pg_typecast_on_load.rb +65 -0
- data/lib/sequel/plugins/validation_helpers.rb +31 -0
- data/lib/sequel/sql.rb +64 -44
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +37 -12
- data/spec/adapters/mysql_spec.rb +39 -75
- data/spec/adapters/oracle_spec.rb +11 -11
- data/spec/adapters/postgres_spec.rb +414 -237
- data/spec/adapters/spec_helper.rb +1 -1
- data/spec/adapters/sqlite_spec.rb +14 -14
- data/spec/core/database_spec.rb +6 -6
- data/spec/core/dataset_spec.rb +169 -205
- data/spec/core/expression_filters_spec.rb +182 -295
- data/spec/core/object_graph_spec.rb +6 -6
- data/spec/core/schema_spec.rb +14 -14
- data/spec/core/spec_helper.rb +1 -0
- data/spec/{extensions/core_extensions_spec.rb → core_extensions_spec.rb} +208 -14
- data/spec/extensions/columns_introspection_spec.rb +5 -5
- data/spec/extensions/hook_class_methods_spec.rb +28 -36
- data/spec/extensions/many_through_many_spec.rb +4 -4
- data/spec/extensions/pg_array_ops_spec.rb +15 -7
- data/spec/extensions/pg_array_spec.rb +81 -48
- data/spec/extensions/pg_auto_parameterize_spec.rb +2 -2
- data/spec/extensions/pg_hstore_ops_spec.rb +13 -9
- data/spec/extensions/pg_hstore_spec.rb +66 -65
- data/spec/extensions/pg_inet_spec.rb +2 -4
- data/spec/extensions/pg_interval_spec.rb +2 -3
- data/spec/extensions/pg_json_spec.rb +20 -18
- data/spec/extensions/pg_range_ops_spec.rb +11 -4
- data/spec/extensions/pg_range_spec.rb +30 -7
- data/spec/extensions/pg_row_ops_spec.rb +48 -0
- data/spec/extensions/pg_row_plugin_spec.rb +45 -0
- data/spec/extensions/pg_row_spec.rb +323 -0
- data/spec/extensions/pg_typecast_on_load_spec.rb +58 -0
- data/spec/extensions/query_literals_spec.rb +11 -11
- data/spec/extensions/query_spec.rb +3 -3
- data/spec/extensions/schema_dumper_spec.rb +20 -4
- data/spec/extensions/schema_spec.rb +18 -41
- data/spec/extensions/select_remove_spec.rb +4 -4
- data/spec/extensions/spec_helper.rb +4 -8
- data/spec/extensions/to_dot_spec.rb +5 -5
- data/spec/extensions/validation_class_methods_spec.rb +28 -16
- data/spec/integration/associations_test.rb +20 -20
- data/spec/integration/dataset_test.rb +98 -98
- data/spec/integration/eager_loader_test.rb +13 -27
- data/spec/integration/plugin_test.rb +5 -5
- data/spec/integration/prepared_statement_test.rb +22 -13
- data/spec/integration/schema_test.rb +28 -18
- data/spec/integration/spec_helper.rb +1 -1
- data/spec/integration/timezone_test.rb +2 -2
- data/spec/integration/type_test.rb +15 -6
- data/spec/model/association_reflection_spec.rb +1 -1
- data/spec/model/associations_spec.rb +4 -4
- data/spec/model/base_spec.rb +5 -5
- data/spec/model/eager_loading_spec.rb +15 -15
- data/spec/model/model_spec.rb +32 -32
- data/spec/model/record_spec.rb +16 -0
- data/spec/model/spec_helper.rb +2 -6
- data/spec/model/validations_spec.rb +1 -1
- metadata +16 -4
@@ -4,9 +4,7 @@ describe "pg_inet extension" do
|
|
4
4
|
ipv6_broken = (IPAddr.new('::1'); false) rescue true
|
5
5
|
before do
|
6
6
|
@db = Sequel.connect('mock://postgres', :quote_identifiers=>false)
|
7
|
-
@db.
|
8
|
-
@db.extension(:pg_array)
|
9
|
-
@db.extension(:pg_inet)
|
7
|
+
@db.extension(:pg_array, :pg_inet)
|
10
8
|
end
|
11
9
|
|
12
10
|
it "should literalize IPAddr v4 instances to strings correctly" do
|
@@ -31,7 +29,7 @@ describe "pg_inet extension" do
|
|
31
29
|
end
|
32
30
|
|
33
31
|
it "should support using IPAddr instances in array types in bound variables" do
|
34
|
-
@db.bound_variable_arg([IPAddr.new('127.0.0.1')]
|
32
|
+
@db.bound_variable_arg(Sequel.pg_array([IPAddr.new('127.0.0.1')]), nil).should == '{"127.0.0.1/32"}'
|
35
33
|
end
|
36
34
|
|
37
35
|
it "should parse inet/cidr type from the schema correctly" do
|
@@ -8,7 +8,6 @@ else
|
|
8
8
|
describe "pg_interval extension" do
|
9
9
|
before do
|
10
10
|
@db = Sequel.connect('mock://postgres', :quote_identifiers=>false)
|
11
|
-
@db.extend(Module.new{def bound_variable_arg(arg, conn) arg end})
|
12
11
|
@db.extension(:pg_array, :pg_interval)
|
13
12
|
end
|
14
13
|
|
@@ -37,8 +36,8 @@ describe "pg_interval extension" do
|
|
37
36
|
end
|
38
37
|
|
39
38
|
it "should support using ActiveSupport::Duration instances in array types in bound variables" do
|
40
|
-
@db.bound_variable_arg([ActiveSupport::Duration.new(0, [[:seconds, 0]])]
|
41
|
-
@db.bound_variable_arg([ActiveSupport::Duration.new(0, [[:seconds, -10.000001], [:minutes, -20], [:days, -3], [:months, -4], [:years, -6]])]
|
39
|
+
@db.bound_variable_arg(Sequel.pg_array([ActiveSupport::Duration.new(0, [[:seconds, 0]])]), nil).should == '{"0"}'
|
40
|
+
@db.bound_variable_arg(Sequel.pg_array([ActiveSupport::Duration.new(0, [[:seconds, -10.000001], [:minutes, -20], [:days, -3], [:months, -4], [:years, -6]])]), nil).should == '{"-6 years -4 months -3 days -20 minutes -10.000001 seconds "}'
|
42
41
|
end
|
43
42
|
|
44
43
|
it "should parse interval type from the schema correctly" do
|
@@ -20,7 +20,6 @@ describe "pg_json extension" do
|
|
20
20
|
end
|
21
21
|
before do
|
22
22
|
@db = Sequel.connect('mock://postgres', :quote_identifiers=>false)
|
23
|
-
@db.extend(Module.new{def bound_variable_arg(arg, conn) arg end})
|
24
23
|
@db.extension(:pg_array, :pg_json)
|
25
24
|
end
|
26
25
|
|
@@ -43,36 +42,39 @@ describe "pg_json extension" do
|
|
43
42
|
end
|
44
43
|
|
45
44
|
it "should literalize HStores to strings correctly" do
|
46
|
-
@db.literal([]
|
47
|
-
@db.literal([1, [2], {'a'=>'b'}]
|
48
|
-
@db.literal({}
|
49
|
-
@db.literal(
|
45
|
+
@db.literal(Sequel.pg_json([])).should == "'[]'::json"
|
46
|
+
@db.literal(Sequel.pg_json([1, [2], {'a'=>'b'}])).should == "'[1,[2],{\"a\":\"b\"}]'::json"
|
47
|
+
@db.literal(Sequel.pg_json({})).should == "'{}'::json"
|
48
|
+
@db.literal(Sequel.pg_json('a'=>'b')).should == "'{\"a\":\"b\"}'::json"
|
50
49
|
end
|
51
50
|
|
52
|
-
it "should have
|
53
|
-
|
51
|
+
it "should have Sequel.pg_json return JSONHash and JSONArray as is" do
|
52
|
+
a = Sequel.pg_json({})
|
53
|
+
Sequel.pg_json(a).should equal(a)
|
54
|
+
a = Sequel.pg_json([])
|
55
|
+
Sequel.pg_json(a).should equal(a)
|
54
56
|
end
|
55
57
|
|
56
|
-
it "should have
|
57
|
-
|
58
|
+
it "should have Sequel.pg_json raise an Error if called with a non-hash or array" do
|
59
|
+
proc{Sequel.pg_json(:a)}.should raise_error(Sequel::Error)
|
58
60
|
end
|
59
61
|
|
60
62
|
it "should have JSONHash#to_hash method for getting underlying hash" do
|
61
|
-
{}.
|
63
|
+
Sequel.pg_json({}).to_hash.should be_a_kind_of(Hash)
|
62
64
|
end
|
63
65
|
|
64
66
|
it "should have JSONArray#to_a method for getting underlying array" do
|
65
|
-
[].
|
67
|
+
Sequel.pg_json([]).to_a.should be_a_kind_of(Array)
|
66
68
|
end
|
67
69
|
|
68
70
|
it "should support using JSONHash and JSONArray as bound variables" do
|
69
71
|
@db.bound_variable_arg(1, nil).should == 1
|
70
|
-
@db.bound_variable_arg([1]
|
71
|
-
@db.bound_variable_arg(
|
72
|
+
@db.bound_variable_arg(Sequel.pg_json([1]), nil).should == '[1]'
|
73
|
+
@db.bound_variable_arg(Sequel.pg_json('a'=>'b'), nil).should == '{"a":"b"}'
|
72
74
|
end
|
73
75
|
|
74
76
|
it "should support using json[] types in bound variables" do
|
75
|
-
@db.bound_variable_arg([[{"a"=>1}].pg_json
|
77
|
+
@db.bound_variable_arg(Sequel.pg_array([Sequel.pg_json([{"a"=>1}]), Sequel.pg_json("b"=>[1, 2])]), nil).should == '{"[{\\"a\\":1}]","{\\"b\\":[1,2]}"}'
|
76
78
|
end
|
77
79
|
|
78
80
|
it "should parse json type from the schema correctly" do
|
@@ -81,16 +83,16 @@ describe "pg_json extension" do
|
|
81
83
|
end
|
82
84
|
|
83
85
|
it "should support typecasting for the json type" do
|
84
|
-
h =
|
85
|
-
a = [1]
|
86
|
+
h = Sequel.pg_json(1=>2)
|
87
|
+
a = Sequel.pg_json([1])
|
86
88
|
@db.typecast_value(:json, h).should equal(h)
|
87
89
|
@db.typecast_value(:json, h.to_hash).should == h
|
88
90
|
@db.typecast_value(:json, h.to_hash).should be_a_kind_of(@hc)
|
89
91
|
@db.typecast_value(:json, a).should equal(a)
|
90
92
|
@db.typecast_value(:json, a.to_a).should == a
|
91
93
|
@db.typecast_value(:json, a.to_a).should be_a_kind_of(@ac)
|
92
|
-
@db.typecast_value(:json, '[]').should == []
|
93
|
-
@db.typecast_value(:json, '{"a": "b"}').should ==
|
94
|
+
@db.typecast_value(:json, '[]').should == Sequel.pg_json([])
|
95
|
+
@db.typecast_value(:json, '{"a": "b"}').should == Sequel.pg_json("a"=>"b")
|
94
96
|
proc{@db.typecast_value(:json, '')}.should raise_error(Sequel::InvalidValue)
|
95
97
|
proc{@db.typecast_value(:json, 1)}.should raise_error(Sequel::InvalidValue)
|
96
98
|
end
|
@@ -3,21 +3,28 @@ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
|
3
3
|
describe "Sequel::Postgres::RangeOp" do
|
4
4
|
before do
|
5
5
|
@ds = Sequel.connect('mock://postgres', :quote_identifiers=>false).dataset
|
6
|
-
@h = :h
|
6
|
+
@h = Sequel.pg_range_op(:h)
|
7
7
|
end
|
8
8
|
|
9
9
|
it "#pg_range should return self" do
|
10
10
|
@h.pg_range.should equal(@h)
|
11
11
|
end
|
12
12
|
|
13
|
-
it "
|
14
|
-
|
13
|
+
it "Sequel.pg_range_op should return argument if already a RangeOp" do
|
14
|
+
Sequel.pg_range_op(@h).should equal(@h)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "Sequel.pg_range should return a new RangeOp if not given a range" do
|
18
|
+
@ds.literal(Sequel.pg_range(:h).lower).should == "lower(h)"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "#pg_range should return a RangeOp for literal strings, and expressions" do
|
15
22
|
@ds.literal(Sequel.function(:b, :h).pg_range.lower).should == "lower(b(h))"
|
16
23
|
@ds.literal(Sequel.lit('h').pg_range.lower).should == "lower(h)"
|
17
24
|
end
|
18
25
|
|
19
26
|
it "PGRange#op should return a RangeOp" do
|
20
|
-
@ds.literal((1..2
|
27
|
+
@ds.literal(Sequel.pg_range(1..2, :numrange).op.lower).should == "lower('[1,2]'::numrange)"
|
21
28
|
end
|
22
29
|
|
23
30
|
it "should define methods for all of the the PostgreSQL range operators" do
|
@@ -1,13 +1,18 @@
|
|
1
1
|
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
2
2
|
|
3
3
|
describe "pg_range extension" do
|
4
|
+
before(:all) do
|
5
|
+
@pg_types = Sequel::Postgres::PG_TYPES.dup
|
6
|
+
end
|
7
|
+
after(:all) do
|
8
|
+
Sequel::Postgres::PG_TYPES.replace(@pg_types)
|
9
|
+
end
|
10
|
+
|
4
11
|
before do
|
5
12
|
@db = Sequel.connect('mock://postgres', :quote_identifiers=>false)
|
6
13
|
@R = Sequel::Postgres::PGRange
|
7
|
-
@db.extend(Module.new{def get_conversion_procs(conn) {} end; def bound_variable_arg(arg, conn) arg end})
|
8
14
|
@db.extend_datasets(Module.new{def supports_timestamp_timezones?; false; end; def supports_timestamp_usecs?; false; end})
|
9
|
-
@db.extension(:pg_array)
|
10
|
-
@db.extension(:pg_range)
|
15
|
+
@db.extension(:pg_array, :pg_range)
|
11
16
|
end
|
12
17
|
|
13
18
|
it "should literalize Range instances to strings correctly" do
|
@@ -204,13 +209,13 @@ describe "pg_range extension" do
|
|
204
209
|
end
|
205
210
|
|
206
211
|
it "should set appropriate timestamp range conversion procs when getting conversion procs" do
|
207
|
-
procs = @db.
|
212
|
+
procs = @db.conversion_procs
|
208
213
|
procs[3908].call('[2011-10-20 11:12:13,2011-10-20 11:12:14]').should == (Time.local(2011, 10, 20, 11, 12, 13)..(Time.local(2011, 10, 20, 11, 12, 14)))
|
209
214
|
procs[3910].call('[2011-10-20 11:12:13,2011-10-20 11:12:14]').should == (Time.local(2011, 10, 20, 11, 12, 13)..(Time.local(2011, 10, 20, 11, 12, 14)))
|
210
215
|
end
|
211
216
|
|
212
217
|
it "should set appropriate timestamp range array conversion procs when getting conversion procs" do
|
213
|
-
procs = @db.
|
218
|
+
procs = @db.conversion_procs
|
214
219
|
procs[3909].call('{"[2011-10-20 11:12:13,2011-10-20 11:12:14]"}').should == [Time.local(2011, 10, 20, 11, 12, 13)..Time.local(2011, 10, 20, 11, 12, 14)]
|
215
220
|
procs[3911].call('{"[2011-10-20 11:12:13,2011-10-20 11:12:14]"}').should == [Time.local(2011, 10, 20, 11, 12, 13)..Time.local(2011, 10, 20, 11, 12, 14)]
|
216
221
|
end
|
@@ -240,8 +245,26 @@ describe "pg_range extension" do
|
|
240
245
|
@r3.db_type.should == 'int8range'
|
241
246
|
end
|
242
247
|
|
243
|
-
it "should be able to be created by
|
244
|
-
(1..2).
|
248
|
+
it "should be able to be created by Sequel.pg_range" do
|
249
|
+
Sequel.pg_range(1..2).should == @r1
|
250
|
+
end
|
251
|
+
|
252
|
+
it "should have Sequel.pg_range be able to take a database type" do
|
253
|
+
Sequel.pg_range(1..2, :int4range).should == @R.new(1, 2, :db_type=>:int4range)
|
254
|
+
end
|
255
|
+
|
256
|
+
it "should have Sequel.pg_range return a PGRange as is" do
|
257
|
+
a = Sequel.pg_range(1..2)
|
258
|
+
Sequel.pg_range(a).should equal(a)
|
259
|
+
end
|
260
|
+
|
261
|
+
it "should have Sequel.pg_range return a new PGRange if the database type differs" do
|
262
|
+
a = Sequel.pg_range(1..2, :int4range)
|
263
|
+
b = Sequel.pg_range(a, :int8range)
|
264
|
+
a.to_range.should == b.to_range
|
265
|
+
a.should_not equal(b)
|
266
|
+
a.db_type.should == :int4range
|
267
|
+
b.db_type.should == :int8range
|
245
268
|
end
|
246
269
|
|
247
270
|
it "should have #initialize raise if requesting an empty range with beginning or ending" do
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
2
|
+
|
3
|
+
describe "Sequel::Postgres::PGRowOp" do
|
4
|
+
before do
|
5
|
+
@db = Sequel.connect('mock://postgres', :quote_identifiers=>false)
|
6
|
+
@a = Sequel.pg_row_op(:a)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "#[] should access members of the composite type" do
|
10
|
+
@db.literal(@a[:b]).should == "(a).b"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "#[] should be chainable" do
|
14
|
+
@db.literal(@a[:b][:c]).should == "((a).b).c"
|
15
|
+
end
|
16
|
+
|
17
|
+
it "#[] should support array access if not given an identifier" do
|
18
|
+
@db.literal(@a[:b][1]).should == "(a).b[1]"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "#[] should be chainable with array access" do
|
22
|
+
@db.literal(@a[1][:b]).should == "(a[1]).b"
|
23
|
+
end
|
24
|
+
|
25
|
+
it "#splat should return a splatted argument" do
|
26
|
+
@db.literal(@a.splat).should == "(a.*)"
|
27
|
+
end
|
28
|
+
|
29
|
+
it "#splat(type) should return a splatted argument cast to given type" do
|
30
|
+
@db.literal(@a.splat(:b)).should == "(a.*)::b"
|
31
|
+
end
|
32
|
+
|
33
|
+
it "#splat should not work on an already accessed composite type" do
|
34
|
+
proc{@a[:a].splat(:b)}.should raise_error(Sequel::Error)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "#pg_row should be callable on literal strings" do
|
38
|
+
@db.literal(Sequel.lit('a').pg_row[:b]).should == "(a).b"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "#pg_row should be callable on Sequel expressions" do
|
42
|
+
@db.literal(Sequel.function(:a).pg_row[:b]).should == "(a()).b"
|
43
|
+
end
|
44
|
+
|
45
|
+
it "Sequel.pg_row should work as well if the pg_row extension is loaded" do
|
46
|
+
@db.literal(Sequel.pg_row(Sequel.function(:a))[:b]).should == "(a()).b"
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
2
|
+
|
3
|
+
describe "Sequel::Plugins::PgRow" do
|
4
|
+
before(:all) do
|
5
|
+
@db = Sequel.connect('mock://postgres', :quote_identifiers=>false)
|
6
|
+
@db.extension(:pg_array)
|
7
|
+
@c = Class.new(Sequel::Model(@db[:address]))
|
8
|
+
@c.columns :street, :city
|
9
|
+
@c.db_schema[:street][:type] = :string
|
10
|
+
@c.db_schema[:city][:type] = :string
|
11
|
+
@db.fetch = [[{:oid=>1098, :typrelid=>2, :typarray=>3}], [{:attname=>'street', :atttypid=>1324}, {:attname=>'city', :atttypid=>1324}]]
|
12
|
+
@c.plugin :pg_row
|
13
|
+
|
14
|
+
@c2 = Class.new(Sequel::Model(@db[:company]))
|
15
|
+
@c2.columns :address
|
16
|
+
@c2.db_schema[:address].merge!(:type=>:pg_row_address)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should set up a parser for the type that creates a model class" do
|
20
|
+
@db.conversion_procs[1098].call('(123 Foo St,Bar City)').should == @c.load(:street=>'123 Foo St', :city=>'Bar City')
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should set up type casting for the type" do
|
24
|
+
@c2.new(:address=>{'street'=>123, 'city'=>:Bar}).address.should == @c.load(:street=>'123', :city=>'Bar')
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should return model instances as is when typecasting to rows" do
|
28
|
+
o = @c.load(:street=>'123', :city=>'Bar')
|
29
|
+
@c2.new(:address=>o).address.should equal(o)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should handle literalizing model instances" do
|
33
|
+
@db.literal(@c.load(:street=>'123 Foo St', :city=>'Bar City')).should == "ROW('123 Foo St', 'Bar City')::address"
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should handle model instances in bound variables" do
|
37
|
+
@db.bound_variable_arg(1, nil).should == 1
|
38
|
+
@db.bound_variable_arg(@c.load(:street=>'123 Foo St', :city=>'Bar City'), nil).should == '("123 Foo St","Bar City")'
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should handle model instances in arrays of bound variables" do
|
42
|
+
@db.bound_variable_arg(1, nil).should == 1
|
43
|
+
@db.bound_variable_arg(Sequel.pg_array([@c.load(:street=>'123 Foo St', :city=>'Bar City')]), nil).should == '{"(\\"123 Foo St\\",\\"Bar City\\")"}'
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,323 @@
|
|
1
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
2
|
+
|
3
|
+
describe "pg_row extension" do
|
4
|
+
before do
|
5
|
+
@db = Sequel.connect('mock://postgres', :quote_identifiers=>false)
|
6
|
+
@db.extension(:pg_array, :pg_row)
|
7
|
+
@m = Sequel::Postgres::PGRow
|
8
|
+
@db.sqls
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should parse record objects as arrays" do
|
12
|
+
a = Sequel::Postgres::PG_TYPES[2249].call("(a,b,c)")
|
13
|
+
a.should be_a_kind_of(@m::ArrayRow)
|
14
|
+
a.to_a.should be_a_kind_of(Array)
|
15
|
+
a[0].should == 'a'
|
16
|
+
a.should == %w'a b c'
|
17
|
+
a.db_type.should == nil
|
18
|
+
@db.literal(a).should == "ROW('a', 'b', 'c')"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should parse arrays of record objects as arrays of arrays" do
|
22
|
+
as = Sequel::Postgres::PG_TYPES[2287].call('{"(a,b,c)","(d,e,f)"}')
|
23
|
+
as.should == [%w'a b c', %w'd e f']
|
24
|
+
as.each do |a|
|
25
|
+
a.should be_a_kind_of(@m::ArrayRow)
|
26
|
+
a.to_a.should be_a_kind_of(Array)
|
27
|
+
a.db_type.should == nil
|
28
|
+
end
|
29
|
+
@db.literal(as).should == "ARRAY[ROW('a', 'b', 'c'),ROW('d', 'e', 'f')]::record[]"
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should be able to register custom parsing of row types as array-like objects" do
|
33
|
+
klass = @m::ArrayRow.subclass(:foo)
|
34
|
+
parser = @m::Parser.new(:converter=>klass)
|
35
|
+
a = parser.call("(a,b,c)")
|
36
|
+
a.should be_a_kind_of(klass)
|
37
|
+
a.to_a.should be_a_kind_of(Array)
|
38
|
+
a[0].should == 'a'
|
39
|
+
a.should == %w'a b c'
|
40
|
+
a.db_type.should == :foo
|
41
|
+
@db.literal(a).should == "ROW('a', 'b', 'c')::foo"
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should be able to register custom parsing of row types as hash-like objects" do
|
45
|
+
klass = @m::HashRow.subclass(:foo, [:a, :b, :c])
|
46
|
+
parser = @m::Parser.new(:converter=>klass, :columns=>[:a, :b, :c])
|
47
|
+
a = parser.call("(a,b,c)")
|
48
|
+
a.should be_a_kind_of(klass)
|
49
|
+
a.to_hash.should be_a_kind_of(Hash)
|
50
|
+
a[:a].should == 'a'
|
51
|
+
a.should == {:a=>'a', :b=>'b', :c=>'c'}
|
52
|
+
a.db_type.should == :foo
|
53
|
+
a.columns.should == [:a, :b, :c]
|
54
|
+
@db.literal(a).should == "ROW('a', 'b', 'c')::foo"
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should raise an error if attempting to literalize a HashRow without column information" do
|
58
|
+
h = @m::HashRow.call(:a=>'a', :b=>'b', :c=>'c')
|
59
|
+
proc{@db.literal(h)}.should raise_error(Sequel::Error)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should be able to manually override db_type per ArrayRow instance" do
|
63
|
+
a = @m::ArrayRow.call(%w'a b c')
|
64
|
+
a.db_type = :foo
|
65
|
+
@db.literal(a).should == "ROW('a', 'b', 'c')::foo"
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should be able to manually override db_type and columns per HashRow instance" do
|
69
|
+
h = @m::HashRow.call(:a=>'a', :c=>'c', :b=>'b')
|
70
|
+
h.db_type = :foo
|
71
|
+
h.columns = [:a, :b, :c]
|
72
|
+
@db.literal(h).should == "ROW('a', 'b', 'c')::foo"
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should correctly split an empty row" do
|
76
|
+
@m::Splitter.new("()").parse.should == [nil]
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should correctly split a row with a single value" do
|
80
|
+
@m::Splitter.new("(1)").parse.should == %w'1'
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should correctly split a row with multiple values" do
|
84
|
+
@m::Splitter.new("(1,2)").parse.should == %w'1 2'
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should correctly NULL values when splitting" do
|
88
|
+
@m::Splitter.new("(1,)").parse.should == ['1', nil]
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should correctly empty string values when splitting" do
|
92
|
+
@m::Splitter.new('(1,"")').parse.should == ['1', '']
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should handle quoted values when splitting" do
|
96
|
+
@m::Splitter.new('("1","2")').parse.should == %w'1 2'
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should handle escaped backslashes in quoted values when splitting" do
|
100
|
+
@m::Splitter.new('("\\\\1","2\\\\")').parse.should == ['\\1', '2\\']
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should handle doubled quotes in quoted values when splitting" do
|
104
|
+
@m::Splitter.new('("""1","2""")').parse.should == ['"1', '2"']
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should correctly convert types when parsing into an array" do
|
108
|
+
@m::Parser.new(:column_converters=>[proc{|s| s*2}, proc{|s| s*3}, proc{|s| s*4}]).call("(a,b,c)").should == %w'aa bbb cccc'
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should correctly convert types into hashes if columns are known" do
|
112
|
+
@m::Parser.new(:columns=>[:a, :b, :c]).call("(a,b,c)").should == {:a=>'a', :b=>'b', :c=>'c'}
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should correctly handle type conversion when converting into hashes" do
|
116
|
+
@m::Parser.new(:column_converters=>[proc{|s| s*2}, proc{|s| s*3}, proc{|s| s*4}], :columns=>[:a, :b, :c]).call("(a,b,c)").should == {:a=>'aa', :b=>'bbb', :c=>'cccc'}
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should correctly wrap arrays when converting" do
|
120
|
+
@m::Parser.new(:converter=>proc{|s| [:foo, s]}).call("(a,b,c)").should == [:foo, %w'a b c']
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should correctly wrap hashes when converting" do
|
124
|
+
@m::Parser.new(:converter=>proc{|s| [:foo, s]}, :columns=>[:a, :b, :c]).call("(a,b,c)").should == [:foo, {:a=>'a', :b=>'b', :c=>'c'}]
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should have parser store reflection information" do
|
128
|
+
p = @m::Parser.new(:oid=>1, :column_oids=>[2], :columns=>[:a], :converter=>Array, :typecaster=>Hash, :column_converters=>[Array])
|
129
|
+
p.oid.should == 1
|
130
|
+
p.column_oids.should == [2]
|
131
|
+
p.columns.should == [:a]
|
132
|
+
p.converter.should == Array
|
133
|
+
p.typecaster.should == Hash
|
134
|
+
p.column_converters.should == [Array]
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should reload registered row types when reseting conversion procs" do
|
138
|
+
db = Sequel.mock(:host=>'postgres')
|
139
|
+
db.extension(:pg_row)
|
140
|
+
db.conversion_procs[4] = p4 = proc{|s| s.to_i}
|
141
|
+
db.conversion_procs[5] = p5 = proc{|s| s * 2}
|
142
|
+
db.sqls
|
143
|
+
db.fetch = [[{:oid=>1, :typrelid=>2, :typarray=>3}], [{:attname=>'bar', :atttypid=>4}, {:attname=>'baz', :atttypid=>5}]]
|
144
|
+
db.register_row_type(:foo)
|
145
|
+
db.sqls.should == ["SELECT pg_type.oid, typrelid, typarray FROM pg_type WHERE ((typtype = 'c') AND (typname = 'foo')) LIMIT 1",
|
146
|
+
"SELECT attname, atttypid FROM pg_attribute WHERE ((attrelid = 2) AND (attnum > 0) AND NOT attisdropped) ORDER BY attnum"]
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should handle ArrayRows and HashRows in bound variables" do
|
150
|
+
@db.bound_variable_arg(1, nil).should == 1
|
151
|
+
@db.bound_variable_arg(@m::ArrayRow.call(["1", "abc\\'\","]), nil).should == '("1","abc\\\\\'\\",")'
|
152
|
+
@db.bound_variable_arg(@m::HashRow.subclass(nil, [:a, :b]).call(:a=>"1", :b=>"abc\\'\","), nil).should == '("1","abc\\\\\'\\",")'
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should handle ArrayRows and HashRows in arrays in bound variables" do
|
156
|
+
@db.bound_variable_arg(1, nil).should == 1
|
157
|
+
@db.bound_variable_arg([@m::ArrayRow.call(["1", "abc\\'\","])], nil).should == '{"(\\"1\\",\\"abc\\\\\\\\\'\\\\\\",\\")"}'
|
158
|
+
@db.bound_variable_arg([@m::HashRow.subclass(nil, [:a, :b]).call(:a=>"1", :b=>"abc\\'\",")], nil).should == '{"(\\"1\\",\\"abc\\\\\\\\\'\\\\\\",\\")"}'
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should allow registering row type parsers by introspecting system tables" do
|
162
|
+
@db.conversion_procs[4] = p4 = proc{|s| s.to_i}
|
163
|
+
@db.conversion_procs[5] = p5 = proc{|s| s * 2}
|
164
|
+
@db.fetch = [[{:oid=>1, :typrelid=>2, :typarray=>3}], [{:attname=>'bar', :atttypid=>4}, {:attname=>'baz', :atttypid=>5}]]
|
165
|
+
@db.register_row_type(:foo)
|
166
|
+
@db.sqls.should == ["SELECT pg_type.oid, typrelid, typarray FROM pg_type WHERE ((typtype = 'c') AND (typname = 'foo')) LIMIT 1",
|
167
|
+
"SELECT attname, atttypid FROM pg_attribute WHERE ((attrelid = 2) AND (attnum > 0) AND NOT attisdropped) ORDER BY attnum"]
|
168
|
+
p1 = @db.conversion_procs[1]
|
169
|
+
p1.columns.should == [:bar, :baz]
|
170
|
+
p1.column_oids.should == [4, 5]
|
171
|
+
p1.column_converters.should == [p4, p5]
|
172
|
+
p1.oid.should == 1
|
173
|
+
@db.send(:schema_column_type, 'foo').should == :pg_row_foo
|
174
|
+
@db.send(:schema_column_type, 'integer').should == :integer
|
175
|
+
|
176
|
+
c = p1.converter
|
177
|
+
c.superclass.should == @m::HashRow
|
178
|
+
c.columns.should == [:bar, :baz]
|
179
|
+
c.db_type.should == :foo
|
180
|
+
p1.typecaster.should == c
|
181
|
+
|
182
|
+
p1.call('(1,b)').should == {:bar=>1, :baz=>'bb'}
|
183
|
+
@db.typecast_value(:pg_row_foo, %w'1 b').should be_a_kind_of(@m::HashRow)
|
184
|
+
@db.typecast_value(:pg_row_foo, %w'1 b').should == {:bar=>'1', :baz=>'b'}
|
185
|
+
@db.typecast_value(:pg_row_foo, :bar=>'1', :baz=>'b').should == {:bar=>'1', :baz=>'b'}
|
186
|
+
@db.literal(p1.call('(1,b)')).should == "ROW(1, 'bb')::foo"
|
187
|
+
end
|
188
|
+
|
189
|
+
it "should allow registering row type parsers for schema qualify types" do
|
190
|
+
@db.conversion_procs[4] = p4 = proc{|s| s.to_i}
|
191
|
+
@db.conversion_procs[5] = p5 = proc{|s| s * 2}
|
192
|
+
@db.fetch = [[{:oid=>1, :typrelid=>2, :typarray=>3}], [{:attname=>'bar', :atttypid=>4}, {:attname=>'baz', :atttypid=>5}]]
|
193
|
+
@db.register_row_type(:foo__bar)
|
194
|
+
@db.sqls.should == ["SELECT pg_type.oid, typrelid, typarray FROM pg_type INNER JOIN pg_namespace ON ((pg_namespace.oid = pg_type.typnamespace) AND (pg_namespace.nspname = 'foo')) WHERE ((typtype = 'c') AND (typname = 'bar')) LIMIT 1",
|
195
|
+
"SELECT attname, atttypid FROM pg_attribute WHERE ((attrelid = 2) AND (attnum > 0) AND NOT attisdropped) ORDER BY attnum"]
|
196
|
+
p1 = @db.conversion_procs[1]
|
197
|
+
p1.columns.should == [:bar, :baz]
|
198
|
+
p1.column_oids.should == [4, 5]
|
199
|
+
p1.column_converters.should == [p4, p5]
|
200
|
+
p1.oid.should == 1
|
201
|
+
|
202
|
+
c = p1.converter
|
203
|
+
c.superclass.should == @m::HashRow
|
204
|
+
c.columns.should == [:bar, :baz]
|
205
|
+
c.db_type.should == :foo__bar
|
206
|
+
p1.typecaster.should == c
|
207
|
+
|
208
|
+
p1.call('(1,b)').should == {:bar=>1, :baz=>'bb'}
|
209
|
+
@db.typecast_value(:pg_row_foo__bar, %w'1 b').should == {:bar=>'1', :baz=>'b'}
|
210
|
+
@db.typecast_value(:pg_row_foo__bar, :bar=>'1', :baz=>'b').should == {:bar=>'1', :baz=>'b'}
|
211
|
+
@db.literal(p1.call('(1,b)')).should == "ROW(1, 'bb')::foo.bar"
|
212
|
+
end
|
213
|
+
|
214
|
+
it "should allow registering with a custom converter" do
|
215
|
+
@db.conversion_procs[4] = p4 = proc{|s| s.to_i}
|
216
|
+
@db.conversion_procs[5] = p5 = proc{|s| s * 2}
|
217
|
+
@db.fetch = [[{:oid=>1, :typrelid=>2, :typarray=>3}], [{:attname=>'bar', :atttypid=>4}, {:attname=>'baz', :atttypid=>5}]]
|
218
|
+
c = proc{|h| [h]}
|
219
|
+
@db.register_row_type(:foo, :converter=>c)
|
220
|
+
o = @db.conversion_procs[1].call('(1,b)')
|
221
|
+
o.should == [{:bar=>1, :baz=>'bb'}]
|
222
|
+
o.first.should be_a_kind_of(Hash)
|
223
|
+
end
|
224
|
+
|
225
|
+
it "should allow registering with a custom typecaster" do
|
226
|
+
@db.conversion_procs[4] = p4 = proc{|s| s.to_i}
|
227
|
+
@db.conversion_procs[5] = p5 = proc{|s| s * 2}
|
228
|
+
@db.fetch = [[{:oid=>1, :typrelid=>2, :typarray=>3}], [{:attname=>'bar', :atttypid=>4}, {:attname=>'baz', :atttypid=>5}]]
|
229
|
+
@db.register_row_type(:foo, :typecaster=>proc{|h| {:bar=>(h[:bar]||0).to_i, :baz=>(h[:baz] || 'a')*2}})
|
230
|
+
@db.typecast_value(:pg_row_foo, %w'1 b').should be_a_kind_of(Hash)
|
231
|
+
@db.typecast_value(:pg_row_foo, %w'1 b').should == {:bar=>1, :baz=>'bb'}
|
232
|
+
@db.typecast_value(:pg_row_foo, :bar=>'1', :baz=>'b').should == {:bar=>1, :baz=>'bb'}
|
233
|
+
@db.typecast_value(:pg_row_foo, 'bar'=>'1', 'baz'=>'b').should == {:bar=>0, :baz=>'aa'}
|
234
|
+
@db.fetch = [[{:oid=>1, :typrelid=>2, :typarray=>3}], [{:attname=>'bar', :atttypid=>4}, {:attname=>'baz', :atttypid=>5}]]
|
235
|
+
@db.register_row_type(:foo, :typecaster=>proc{|h| {:bar=>(h[:bar] || h['bar'] || 0).to_i, :baz=>(h[:baz] || h['baz'] || 'a')*2}})
|
236
|
+
@db.typecast_value(:pg_row_foo, %w'1 b').should == {:bar=>1, :baz=>'bb'}
|
237
|
+
@db.typecast_value(:pg_row_foo, :bar=>'1', :baz=>'b').should == {:bar=>1, :baz=>'bb'}
|
238
|
+
@db.typecast_value(:pg_row_foo, 'bar'=>'1', 'baz'=>'b').should == {:bar=>1, :baz=>'bb'}
|
239
|
+
end
|
240
|
+
|
241
|
+
it "should handle conversion procs that aren't added until later" do
|
242
|
+
@db.conversion_procs[5] = p5 = proc{|s| s * 2}
|
243
|
+
@db.fetch = [[{:oid=>1, :typrelid=>2, :typarray=>3}], [{:attname=>'bar', :atttypid=>4}, {:attname=>'baz', :atttypid=>5}]]
|
244
|
+
c = proc{|h| [h]}
|
245
|
+
@db.register_row_type(:foo, :converter=>c)
|
246
|
+
@db.conversion_procs[4] = p4 = proc{|s| s.to_i}
|
247
|
+
@db.conversion_procs[1].call('(1,b)').should == [{:bar=>1, :baz=>'bb'}]
|
248
|
+
end
|
249
|
+
|
250
|
+
it "should registering array type for row type if type has an array oid" do
|
251
|
+
@db.conversion_procs[4] = p4 = proc{|s| s.to_i}
|
252
|
+
@db.conversion_procs[5] = p5 = proc{|s| s * 2}
|
253
|
+
@db.fetch = [[{:oid=>1, :typrelid=>2, :typarray=>3}], [{:attname=>'bar', :atttypid=>4}, {:attname=>'baz', :atttypid=>5}]]
|
254
|
+
@db.register_row_type(:foo, :typecaster=>proc{|h| {:bar=>(h[:bar]||0).to_i, :baz=>(h[:baz] || 'a')*2}})
|
255
|
+
p3 = @db.conversion_procs[3]
|
256
|
+
|
257
|
+
p3.call('{"(1,b)"}').should == [{:bar=>1, :baz=>'bb'}]
|
258
|
+
@db.literal(p3.call('{"(1,b)"}')).should == "ARRAY[ROW(1, 'bb')::foo]::foo[]"
|
259
|
+
@db.typecast_value(:foo_array, [{:bar=>'1', :baz=>'b'}]).should == [{:bar=>1, :baz=>'bb'}]
|
260
|
+
end
|
261
|
+
|
262
|
+
it "should allow creating unregisted row types via Database#row_type" do
|
263
|
+
@db.literal(@db.row_type(:foo, [1, 2])).should == 'ROW(1, 2)::foo'
|
264
|
+
end
|
265
|
+
|
266
|
+
it "should allow typecasting of registered row types via Database#row_type" do
|
267
|
+
@db.conversion_procs[4] = p4 = proc{|s| s.to_i}
|
268
|
+
@db.conversion_procs[5] = p5 = proc{|s| s * 2}
|
269
|
+
@db.fetch = [[{:oid=>1, :typrelid=>2, :typarray=>3}], [{:attname=>'bar', :atttypid=>4}, {:attname=>'baz', :atttypid=>5}]]
|
270
|
+
@db.register_row_type(:foo, :typecaster=>proc{|h| @m::HashRow.subclass(:foo, [:bar, :baz]).new({:bar=>(h[:bar]||0).to_i, :baz=>(h[:baz] || 'a')*2})})
|
271
|
+
@db.literal(@db.row_type(:foo, ['1', 'b'])).should == "ROW(1, 'bb')::foo"
|
272
|
+
@db.literal(@db.row_type(:foo, {:bar=>'1', :baz=>'b'})).should == "ROW(1, 'bb')::foo"
|
273
|
+
end
|
274
|
+
|
275
|
+
it "should allow parsing when typecasting registered row types via Database#row_type" do
|
276
|
+
@db.conversion_procs[4] = p4 = proc{|s| s.to_i}
|
277
|
+
@db.conversion_procs[5] = p5 = proc{|s| s * 2}
|
278
|
+
@db.fetch = [[{:oid=>1, :typrelid=>2, :typarray=>3}], [{:attname=>'bar', :atttypid=>4}, {:attname=>'baz', :atttypid=>5}]]
|
279
|
+
@db.register_row_type(:foo, :typecaster=>proc{|h| @m::HashRow.subclass(:foo, [:bar, :baz]).new(:bar=>(h[:bar]||0).to_i, :baz=>(h[:baz] || 'a')*2)})
|
280
|
+
@db.literal(@db.row_type(:foo, ['1', 'b'])).should == "ROW(1, 'bb')::foo"
|
281
|
+
end
|
282
|
+
|
283
|
+
it "should raise an error if attempt to use Database#row_type with an unregistered type and hash" do
|
284
|
+
proc{@db.literal(@db.row_type(:foo, {:bar=>'1', :baz=>'b'}))}.should raise_error(Sequel::Error)
|
285
|
+
end
|
286
|
+
|
287
|
+
it "should raise an error if attempt to use Database#row_type with an unhandled type" do
|
288
|
+
proc{@db.literal(@db.row_type(:foo, 1))}.should raise_error(Sequel::Error)
|
289
|
+
end
|
290
|
+
|
291
|
+
it "should return ArrayRow and HashRow values as-is" do
|
292
|
+
h = @m::HashRow.call(:a=>1)
|
293
|
+
a = @m::ArrayRow.call([1])
|
294
|
+
@db.row_type(:foo, h).should equal(h)
|
295
|
+
@db.row_type(:foo, a).should equal(a)
|
296
|
+
end
|
297
|
+
|
298
|
+
it "should have Sequel.pg_row return a plain ArrayRow" do
|
299
|
+
@db.literal(Sequel.pg_row([1, 2, 3])).should == 'ROW(1, 2, 3)'
|
300
|
+
end
|
301
|
+
|
302
|
+
it "should raise an error if attempting to typecast a hash for a parser without columns" do
|
303
|
+
proc{@m::Parser.new.typecast(:a=>1)}.should raise_error(Sequel::Error)
|
304
|
+
end
|
305
|
+
|
306
|
+
it "should raise an error if attempting to typecast a unhandled value for a parser" do
|
307
|
+
proc{@m::Parser.new.typecast(1)}.should raise_error(Sequel::Error)
|
308
|
+
end
|
309
|
+
|
310
|
+
it "should handle typecasting for a parser without a typecaster" do
|
311
|
+
@m::Parser.new.typecast([1]).should == [1]
|
312
|
+
end
|
313
|
+
|
314
|
+
it "should raise an error if no columns are returned when registering a custom row type" do
|
315
|
+
@db.fetch = [[{:oid=>1, :typrelid=>2, :typarray=>3}]]
|
316
|
+
proc{@db.register_row_type(:foo)}.should raise_error(Sequel::Error)
|
317
|
+
end
|
318
|
+
|
319
|
+
it "should raise an error when registering a custom row type if the type is found found" do
|
320
|
+
@db.fetch = []
|
321
|
+
proc{@db.register_row_type(:foo)}.should raise_error(Sequel::Error)
|
322
|
+
end
|
323
|
+
end
|