sequel 3.36.1 → 3.37.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 +84 -0
- data/Rakefile +13 -0
- data/bin/sequel +12 -16
- data/doc/advanced_associations.rdoc +36 -67
- data/doc/association_basics.rdoc +11 -16
- data/doc/release_notes/3.37.0.txt +338 -0
- data/doc/schema_modification.rdoc +4 -0
- data/lib/sequel/adapters/jdbc/h2.rb +1 -1
- data/lib/sequel/adapters/jdbc/postgresql.rb +26 -8
- data/lib/sequel/adapters/mysql2.rb +4 -3
- data/lib/sequel/adapters/odbc/mssql.rb +2 -2
- data/lib/sequel/adapters/postgres.rb +4 -60
- data/lib/sequel/adapters/shared/mssql.rb +2 -1
- data/lib/sequel/adapters/shared/mysql.rb +0 -5
- data/lib/sequel/adapters/shared/postgres.rb +68 -2
- data/lib/sequel/adapters/shared/sqlite.rb +17 -1
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +12 -1
- data/lib/sequel/adapters/utils/pg_types.rb +76 -0
- data/lib/sequel/core.rb +13 -0
- data/lib/sequel/database/misc.rb +41 -1
- data/lib/sequel/database/schema_generator.rb +23 -10
- data/lib/sequel/database/schema_methods.rb +26 -4
- data/lib/sequel/dataset/graph.rb +2 -1
- data/lib/sequel/dataset/query.rb +62 -2
- data/lib/sequel/extensions/_pretty_table.rb +7 -3
- data/lib/sequel/extensions/arbitrary_servers.rb +5 -4
- data/lib/sequel/extensions/blank.rb +4 -0
- data/lib/sequel/extensions/columns_introspection.rb +13 -2
- data/lib/sequel/extensions/core_extensions.rb +6 -0
- data/lib/sequel/extensions/eval_inspect.rb +158 -0
- data/lib/sequel/extensions/inflector.rb +4 -0
- data/lib/sequel/extensions/looser_typecasting.rb +5 -4
- data/lib/sequel/extensions/migration.rb +4 -1
- data/lib/sequel/extensions/named_timezones.rb +4 -0
- data/lib/sequel/extensions/null_dataset.rb +4 -0
- data/lib/sequel/extensions/pagination.rb +4 -0
- data/lib/sequel/extensions/pg_array.rb +219 -168
- data/lib/sequel/extensions/pg_array_ops.rb +7 -2
- data/lib/sequel/extensions/pg_auto_parameterize.rb +10 -4
- data/lib/sequel/extensions/pg_hstore.rb +3 -1
- data/lib/sequel/extensions/pg_hstore_ops.rb +7 -2
- data/lib/sequel/extensions/pg_inet.rb +28 -3
- data/lib/sequel/extensions/pg_interval.rb +192 -0
- data/lib/sequel/extensions/pg_json.rb +21 -9
- data/lib/sequel/extensions/pg_range.rb +487 -0
- data/lib/sequel/extensions/pg_range_ops.rb +122 -0
- data/lib/sequel/extensions/pg_statement_cache.rb +3 -2
- data/lib/sequel/extensions/pretty_table.rb +12 -1
- data/lib/sequel/extensions/query.rb +4 -0
- data/lib/sequel/extensions/query_literals.rb +6 -6
- data/lib/sequel/extensions/schema_dumper.rb +39 -38
- data/lib/sequel/extensions/select_remove.rb +4 -0
- data/lib/sequel/extensions/server_block.rb +3 -2
- data/lib/sequel/extensions/split_array_nil.rb +65 -0
- data/lib/sequel/extensions/sql_expr.rb +4 -0
- data/lib/sequel/extensions/string_date_time.rb +4 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +9 -3
- data/lib/sequel/extensions/to_dot.rb +4 -0
- data/lib/sequel/model/associations.rb +150 -91
- data/lib/sequel/plugins/identity_map.rb +2 -2
- data/lib/sequel/plugins/list.rb +1 -0
- data/lib/sequel/plugins/many_through_many.rb +33 -32
- data/lib/sequel/plugins/nested_attributes.rb +11 -3
- data/lib/sequel/plugins/rcte_tree.rb +2 -2
- data/lib/sequel/plugins/schema.rb +1 -1
- data/lib/sequel/sql.rb +14 -14
- data/lib/sequel/version.rb +2 -2
- data/spec/adapters/mysql_spec.rb +25 -0
- data/spec/adapters/postgres_spec.rb +572 -28
- data/spec/adapters/sqlite_spec.rb +16 -1
- data/spec/core/database_spec.rb +61 -2
- data/spec/core/dataset_spec.rb +92 -0
- data/spec/core/expression_filters_spec.rb +12 -0
- data/spec/extensions/arbitrary_servers_spec.rb +1 -1
- data/spec/extensions/boolean_readers_spec.rb +25 -25
- data/spec/extensions/eval_inspect_spec.rb +58 -0
- data/spec/extensions/json_serializer_spec.rb +0 -6
- data/spec/extensions/list_spec.rb +1 -1
- data/spec/extensions/looser_typecasting_spec.rb +7 -7
- data/spec/extensions/many_through_many_spec.rb +81 -0
- data/spec/extensions/nested_attributes_spec.rb +21 -4
- data/spec/extensions/pg_array_ops_spec.rb +1 -11
- data/spec/extensions/pg_array_spec.rb +181 -90
- data/spec/extensions/pg_auto_parameterize_spec.rb +3 -3
- data/spec/extensions/pg_hstore_spec.rb +1 -3
- data/spec/extensions/pg_inet_spec.rb +6 -1
- data/spec/extensions/pg_interval_spec.rb +73 -0
- data/spec/extensions/pg_json_spec.rb +5 -9
- data/spec/extensions/pg_range_ops_spec.rb +49 -0
- data/spec/extensions/pg_range_spec.rb +372 -0
- data/spec/extensions/pg_statement_cache_spec.rb +1 -2
- data/spec/extensions/query_literals_spec.rb +1 -2
- data/spec/extensions/schema_dumper_spec.rb +48 -89
- data/spec/extensions/serialization_spec.rb +1 -5
- data/spec/extensions/server_block_spec.rb +2 -2
- data/spec/extensions/spec_helper.rb +12 -2
- data/spec/extensions/split_array_nil_spec.rb +24 -0
- data/spec/integration/associations_test.rb +4 -4
- data/spec/integration/database_test.rb +2 -2
- data/spec/integration/dataset_test.rb +4 -4
- data/spec/integration/eager_loader_test.rb +6 -6
- data/spec/integration/plugin_test.rb +2 -2
- data/spec/integration/spec_helper.rb +2 -2
- data/spec/model/association_reflection_spec.rb +5 -0
- data/spec/model/associations_spec.rb +156 -49
- data/spec/model/eager_loading_spec.rb +137 -2
- data/spec/model/model_spec.rb +10 -10
- metadata +15 -2
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper.rb')
|
|
2
2
|
|
|
3
3
|
unless defined?(SQLITE_DB)
|
|
4
|
-
|
|
4
|
+
unless defined? SQLITE_URL
|
|
5
|
+
if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
|
|
6
|
+
SQLITE_URL = 'jdbc:sqlite::memory:'
|
|
7
|
+
else
|
|
8
|
+
SQLITE_URL = 'sqlite:/'
|
|
9
|
+
end
|
|
10
|
+
end
|
|
5
11
|
SQLITE_DB = Sequel.connect(ENV['SEQUEL_SQLITE_SPEC_DB']||SQLITE_URL)
|
|
6
12
|
end
|
|
7
13
|
INTEGRATION_DB = SQLITE_DB unless defined?(INTEGRATION_DB)
|
|
@@ -49,6 +55,15 @@ describe "An SQLite database" do
|
|
|
49
55
|
@db.get(Sequel.like('a', 'A')).to_s.should == '0'
|
|
50
56
|
end
|
|
51
57
|
|
|
58
|
+
specify "should support casting to Date by using the date function" do
|
|
59
|
+
@db.get('2012-10-20 11:12:13'.cast(Date)).should == '2012-10-20'
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
specify "should support casting to Time or DateTime by using the datetime function" do
|
|
63
|
+
@db.get('2012-10-20'.cast(Time)).should == '2012-10-20 00:00:00'
|
|
64
|
+
@db.get('2012-10-20'.cast(DateTime)).should == '2012-10-20 00:00:00'
|
|
65
|
+
end
|
|
66
|
+
|
|
52
67
|
specify "should provide the SQLite version as an integer" do
|
|
53
68
|
@db.sqlite_version.should be_a_kind_of(Integer)
|
|
54
69
|
end
|
data/spec/core/database_spec.rb
CHANGED
|
@@ -1985,8 +1985,9 @@ end
|
|
|
1985
1985
|
describe "Database#schema_autoincrementing_primary_key?" do
|
|
1986
1986
|
specify "should indicate whether the parsed schema row indicates a primary key" do
|
|
1987
1987
|
m = Sequel::Database.new.method(:schema_autoincrementing_primary_key?)
|
|
1988
|
-
m.call(:primary_key=>true).should == true
|
|
1989
|
-
m.call(:primary_key=>
|
|
1988
|
+
m.call(:primary_key=>true, :db_type=>'integer').should == true
|
|
1989
|
+
m.call(:primary_key=>true, :db_type=>'varchar(255)').should == false
|
|
1990
|
+
m.call(:primary_key=>false, :db_type=>'integer').should == false
|
|
1990
1991
|
end
|
|
1991
1992
|
end
|
|
1992
1993
|
|
|
@@ -2124,3 +2125,61 @@ describe "Database#column_schema_to_ruby_default" do
|
|
|
2124
2125
|
p["((-12.1))", :decimal].should == BigDecimal.new('-12.1')
|
|
2125
2126
|
end
|
|
2126
2127
|
end
|
|
2128
|
+
|
|
2129
|
+
describe "Database extensions" do
|
|
2130
|
+
before(:all) do
|
|
2131
|
+
class << Sequel
|
|
2132
|
+
alias _extension extension
|
|
2133
|
+
def extension(*)
|
|
2134
|
+
end
|
|
2135
|
+
end
|
|
2136
|
+
end
|
|
2137
|
+
after(:all) do
|
|
2138
|
+
class << Sequel
|
|
2139
|
+
alias extension _extension
|
|
2140
|
+
end
|
|
2141
|
+
end
|
|
2142
|
+
before do
|
|
2143
|
+
@db = Sequel.mock
|
|
2144
|
+
end
|
|
2145
|
+
|
|
2146
|
+
specify "should be able to register an extension with a module Database#extension extend the module" do
|
|
2147
|
+
Sequel::Database.register_extension(:foo, Module.new{def a; 1; end})
|
|
2148
|
+
@db.extension(:foo).a.should == 1
|
|
2149
|
+
end
|
|
2150
|
+
|
|
2151
|
+
specify "should be able to register an extension with a block and Database#extension call the block" do
|
|
2152
|
+
@db.quote_identifiers = false
|
|
2153
|
+
Sequel::Database.register_extension(:foo){|db| db.quote_identifiers = true}
|
|
2154
|
+
@db.extension(:foo).quote_identifiers?.should be_true
|
|
2155
|
+
end
|
|
2156
|
+
|
|
2157
|
+
specify "should be able to register an extension with a callable and Database#extension call the callable" do
|
|
2158
|
+
@db.quote_identifiers = false
|
|
2159
|
+
Sequel::Database.register_extension(:foo, proc{|db| db.quote_identifiers = true})
|
|
2160
|
+
@db.extension(:foo).quote_identifiers?.should be_true
|
|
2161
|
+
end
|
|
2162
|
+
|
|
2163
|
+
specify "should be able to load multiple extensions in the same call" do
|
|
2164
|
+
@db.quote_identifiers = false
|
|
2165
|
+
@db.identifier_input_method = :downcase
|
|
2166
|
+
Sequel::Database.register_extension(:foo, proc{|db| db.quote_identifiers = true})
|
|
2167
|
+
Sequel::Database.register_extension(:bar, proc{|db| db.identifier_input_method = nil})
|
|
2168
|
+
@db.extension(:foo, :bar)
|
|
2169
|
+
@db.quote_identifiers?.should be_true
|
|
2170
|
+
@db.identifier_input_method.should be_nil
|
|
2171
|
+
end
|
|
2172
|
+
|
|
2173
|
+
specify "should return the receiver" do
|
|
2174
|
+
Sequel::Database.register_extension(:foo, Module.new{def a; 1; end})
|
|
2175
|
+
@db.extension(:foo).should equal(@db)
|
|
2176
|
+
end
|
|
2177
|
+
|
|
2178
|
+
specify "should raise an Error if registering with both a module and a block" do
|
|
2179
|
+
proc{Sequel::Database.register_extension(:foo, Module.new){}}.should raise_error(Sequel::Error)
|
|
2180
|
+
end
|
|
2181
|
+
|
|
2182
|
+
specify "should raise an Error if attempting to load an incompatible extension" do
|
|
2183
|
+
proc{@db.extension(:foo2)}.should raise_error(Sequel::Error)
|
|
2184
|
+
end
|
|
2185
|
+
end
|
data/spec/core/dataset_spec.rb
CHANGED
|
@@ -2152,6 +2152,14 @@ describe "Dataset#join_table" do
|
|
|
2152
2152
|
@d.from('stats').join('players', {:id => :player_id}, :implicit_qualifier=>:p).sql.should == 'SELECT * FROM "stats" INNER JOIN "players" ON ("players"."id" = "p"."player_id")'
|
|
2153
2153
|
end
|
|
2154
2154
|
|
|
2155
|
+
specify "should not qualify if :qualify=>false option is given" do
|
|
2156
|
+
@d.from('stats').join(:players, {:id => :player_id}, :qualify=>false).sql.should == 'SELECT * FROM "stats" INNER JOIN "players" ON ("id" = "player_id")'
|
|
2157
|
+
end
|
|
2158
|
+
|
|
2159
|
+
specify "should do deep qualification if :qualify=>:deep option is given" do
|
|
2160
|
+
@d.from('stats').join(:players, {Sequel.function(:f, :id) => Sequel.subscript(:player_id, 0)}, :qualify=>:deep).sql.should == 'SELECT * FROM "stats" INNER JOIN "players" ON (f("players"."id") = "stats"."player_id"[0])'
|
|
2161
|
+
end
|
|
2162
|
+
|
|
2155
2163
|
specify "should allow for arbitrary conditions in the JOIN clause" do
|
|
2156
2164
|
@d.join_table(:left_outer, :categories, :status => 0).sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."status" = 0)'
|
|
2157
2165
|
@d.join_table(:left_outer, :categories, :categorizable_type => "Post").sql.should == 'SELECT * FROM "items" LEFT OUTER JOIN "categories" ON ("categories"."categorizable_type" = \'Post\')'
|
|
@@ -4306,3 +4314,87 @@ describe "Dataset feature defaults" do
|
|
|
4306
4314
|
Sequel::Database.new.dataset.send(:offset_returns_row_number_column?).should be_false
|
|
4307
4315
|
end
|
|
4308
4316
|
end
|
|
4317
|
+
|
|
4318
|
+
describe "Dataset extensions" do
|
|
4319
|
+
before(:all) do
|
|
4320
|
+
class << Sequel
|
|
4321
|
+
alias _extension extension
|
|
4322
|
+
def extension(*)
|
|
4323
|
+
end
|
|
4324
|
+
end
|
|
4325
|
+
end
|
|
4326
|
+
after(:all) do
|
|
4327
|
+
class << Sequel
|
|
4328
|
+
alias extension _extension
|
|
4329
|
+
end
|
|
4330
|
+
end
|
|
4331
|
+
before do
|
|
4332
|
+
@ds = Sequel::Dataset.new(nil)
|
|
4333
|
+
end
|
|
4334
|
+
|
|
4335
|
+
specify "should be able to register an extension with a module Database#extension extend the module" do
|
|
4336
|
+
Sequel::Dataset.register_extension(:foo, Module.new{def a; 1; end})
|
|
4337
|
+
@ds.extension(:foo).a.should == 1
|
|
4338
|
+
end
|
|
4339
|
+
|
|
4340
|
+
specify "should be able to register an extension with a block and Database#extension call the block" do
|
|
4341
|
+
@ds.quote_identifiers = false
|
|
4342
|
+
Sequel::Dataset.register_extension(:foo){|db| db.quote_identifiers = true}
|
|
4343
|
+
@ds.extension(:foo).quote_identifiers?.should be_true
|
|
4344
|
+
end
|
|
4345
|
+
|
|
4346
|
+
specify "should be able to register an extension with a callable and Database#extension call the callable" do
|
|
4347
|
+
@ds.quote_identifiers = false
|
|
4348
|
+
Sequel::Dataset.register_extension(:foo, proc{|db| db.quote_identifiers = true})
|
|
4349
|
+
@ds.extension(:foo).quote_identifiers?.should be_true
|
|
4350
|
+
end
|
|
4351
|
+
|
|
4352
|
+
specify "should be able to load multiple extensions in the same call" do
|
|
4353
|
+
@ds.quote_identifiers = false
|
|
4354
|
+
@ds.identifier_input_method = :downcase
|
|
4355
|
+
Sequel::Dataset.register_extension(:foo, proc{|ds| ds.quote_identifiers = true})
|
|
4356
|
+
Sequel::Dataset.register_extension(:bar, proc{|ds| ds.identifier_input_method = nil})
|
|
4357
|
+
ds = @ds.extension(:foo, :bar)
|
|
4358
|
+
ds.quote_identifiers?.should be_true
|
|
4359
|
+
ds.identifier_input_method.should be_nil
|
|
4360
|
+
end
|
|
4361
|
+
|
|
4362
|
+
specify "should have #extension not modify the receiver" do
|
|
4363
|
+
Sequel::Dataset.register_extension(:foo, Module.new{def a; 1; end})
|
|
4364
|
+
@ds.extension(:foo)
|
|
4365
|
+
proc{@ds.a}.should raise_error(NoMethodError)
|
|
4366
|
+
end
|
|
4367
|
+
|
|
4368
|
+
specify "should have #extension not return a cloned dataset" do
|
|
4369
|
+
@ds.extend(Module.new{def b; 2; end})
|
|
4370
|
+
Sequel::Dataset.register_extension(:foo, Module.new{def a; 1; end})
|
|
4371
|
+
v = @ds.extension(:foo)
|
|
4372
|
+
v.should_not equal(@ds)
|
|
4373
|
+
v.should be_a_kind_of(Sequel::Dataset)
|
|
4374
|
+
v.b.should == 2
|
|
4375
|
+
end
|
|
4376
|
+
|
|
4377
|
+
specify "should have #extension! modify the receiver" do
|
|
4378
|
+
Sequel::Dataset.register_extension(:foo, Module.new{def a; 1; end})
|
|
4379
|
+
@ds.extension!(:foo)
|
|
4380
|
+
@ds.a.should == 1
|
|
4381
|
+
end
|
|
4382
|
+
|
|
4383
|
+
specify "should have #extension! return the receiver" do
|
|
4384
|
+
Sequel::Dataset.register_extension(:foo, Module.new{def a; 1; end})
|
|
4385
|
+
@ds.extension!(:foo).should equal(@ds)
|
|
4386
|
+
end
|
|
4387
|
+
|
|
4388
|
+
specify "should register a Database extension for modifying all datasets when registering with a module" do
|
|
4389
|
+
Sequel::Dataset.register_extension(:foo, Module.new{def a; 1; end})
|
|
4390
|
+
Sequel.mock.extension(:foo).dataset.a.should == 1
|
|
4391
|
+
end
|
|
4392
|
+
|
|
4393
|
+
specify "should raise an Error if registering with both a module and a block" do
|
|
4394
|
+
proc{Sequel::Dataset.register_extension(:foo, Module.new){}}.should raise_error(Sequel::Error)
|
|
4395
|
+
end
|
|
4396
|
+
|
|
4397
|
+
specify "should raise an Error if attempting to load an incompatible extension" do
|
|
4398
|
+
proc{@ds.extension(:foo2)}.should raise_error(Sequel::Error)
|
|
4399
|
+
end
|
|
4400
|
+
end
|
|
@@ -1042,3 +1042,15 @@ describe Sequel::SQL::Subscript do
|
|
|
1042
1042
|
@ds.literal(s).should == 'a[1][2]'
|
|
1043
1043
|
end
|
|
1044
1044
|
end
|
|
1045
|
+
|
|
1046
|
+
describe "Sequel.recursive_map" do
|
|
1047
|
+
specify "should recursively convert an array using a callable" do
|
|
1048
|
+
Sequel.recursive_map(['1'], proc{|s| s.to_i}).should == [1]
|
|
1049
|
+
Sequel.recursive_map([['1']], proc{|s| s.to_i}).should == [[1]]
|
|
1050
|
+
end
|
|
1051
|
+
|
|
1052
|
+
specify "should not call callable if value is nil" do
|
|
1053
|
+
Sequel.recursive_map([nil], proc{|s| s.to_i}).should == [nil]
|
|
1054
|
+
Sequel.recursive_map([[nil]], proc{|s| s.to_i}).should == [[nil]]
|
|
1055
|
+
end
|
|
1056
|
+
end
|
|
@@ -3,7 +3,7 @@ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
|
|
3
3
|
describe "arbtirary servers" do
|
|
4
4
|
before do
|
|
5
5
|
@db = Sequel.mock(:servers=>{})
|
|
6
|
-
@db.
|
|
6
|
+
@db.extension :arbitrary_servers
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
specify "should allow arbitrary server options using a hash" do
|
|
@@ -4,12 +4,12 @@ describe Sequel::Model, "BooleanReaders plugin" do
|
|
|
4
4
|
before do
|
|
5
5
|
@db = Sequel::Database.new({})
|
|
6
6
|
def @db.schema(*args)
|
|
7
|
-
[[:id, {}], [:
|
|
7
|
+
[[:id, {}], [:z, {:type=>:integer, :db_type=>'tinyint(1)'}], [:b, {:type=>:boolean, :db_type=>'boolean'}]]
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
@c = Class.new(Sequel::Model(@db[:items]))
|
|
11
11
|
@p = proc do
|
|
12
|
-
@columns = [:id, :b, :
|
|
12
|
+
@columns = [:id, :b, :z]
|
|
13
13
|
def columns; @columns; end
|
|
14
14
|
end
|
|
15
15
|
@c.instance_eval(&@p)
|
|
@@ -29,7 +29,7 @@ describe Sequel::Model, "BooleanReaders plugin" do
|
|
|
29
29
|
|
|
30
30
|
specify "should not create attribute? readers for non-boolean attributes" do
|
|
31
31
|
@c.plugin(:boolean_readers)
|
|
32
|
-
proc{@c.new.
|
|
32
|
+
proc{@c.new.z?}.should raise_error(NoMethodError)
|
|
33
33
|
proc{@c.new.id?}.should raise_error(NoMethodError)
|
|
34
34
|
end
|
|
35
35
|
|
|
@@ -37,17 +37,17 @@ describe Sequel::Model, "BooleanReaders plugin" do
|
|
|
37
37
|
@c.plugin(:boolean_readers){|c| db_schema[c][:db_type] == 'tinyint(1)'}
|
|
38
38
|
proc{@c.new.b?}.should raise_error(NoMethodError)
|
|
39
39
|
o = @c.new
|
|
40
|
-
o.
|
|
41
|
-
o.
|
|
42
|
-
o.
|
|
43
|
-
o.
|
|
44
|
-
o.
|
|
45
|
-
o.
|
|
46
|
-
o.
|
|
47
|
-
o.
|
|
48
|
-
o.
|
|
49
|
-
o.
|
|
50
|
-
o.
|
|
40
|
+
o.z.should == nil
|
|
41
|
+
o.z?.should == nil
|
|
42
|
+
o.z = '1'
|
|
43
|
+
o.z.should == 1
|
|
44
|
+
o.z?.should == true
|
|
45
|
+
o.z = '0'
|
|
46
|
+
o.z.should == 0
|
|
47
|
+
o.z?.should == false
|
|
48
|
+
o.z = ''
|
|
49
|
+
o.z.should == nil
|
|
50
|
+
o.z?.should == nil
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
specify "should create boolean readers when set_dataset is defined" do
|
|
@@ -70,17 +70,17 @@ describe Sequel::Model, "BooleanReaders plugin" do
|
|
|
70
70
|
c.plugin(:boolean_readers){|x| db_schema[x][:db_type] == 'tinyint(1)'}
|
|
71
71
|
c.set_dataset(@db[:a])
|
|
72
72
|
o = c.new
|
|
73
|
-
o.
|
|
74
|
-
o.
|
|
75
|
-
o.
|
|
76
|
-
o.
|
|
77
|
-
o.
|
|
78
|
-
o.
|
|
79
|
-
o.
|
|
80
|
-
o.
|
|
81
|
-
o.
|
|
82
|
-
o.
|
|
83
|
-
o.
|
|
73
|
+
o.z.should == nil
|
|
74
|
+
o.z?.should == nil
|
|
75
|
+
o.z = '1'
|
|
76
|
+
o.z.should == 1
|
|
77
|
+
o.z?.should == true
|
|
78
|
+
o.z = '0'
|
|
79
|
+
o.z.should == 0
|
|
80
|
+
o.z?.should == false
|
|
81
|
+
o.z = ''
|
|
82
|
+
o.z.should == nil
|
|
83
|
+
o.z?.should == nil
|
|
84
84
|
proc{o.b?}.should raise_error(NoMethodError)
|
|
85
85
|
end
|
|
86
86
|
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
|
2
|
+
|
|
3
|
+
describe "eval_inspect extension" do
|
|
4
|
+
before do
|
|
5
|
+
@ds = Sequel.mock.dataset
|
|
6
|
+
@ds.meta_def(:supports_window_functions?){true}
|
|
7
|
+
@ds.meta_def(:literal_blob_append){|sql, s| sql << "X'#{s}'"}
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
specify "should make eval(obj.inspect) == obj for all Sequel::SQL::Expression subclasses" do
|
|
11
|
+
[
|
|
12
|
+
# Objects with components where eval(inspect) == self
|
|
13
|
+
Sequel::SQL::AliasedExpression.new(:b, :a),
|
|
14
|
+
Sequel::SQL::CaseExpression.new({:b=>:a}, :c),
|
|
15
|
+
Sequel::SQL::CaseExpression.new({:b=>:a}, :c, :d),
|
|
16
|
+
Sequel::SQL::Cast.new(:a, :b),
|
|
17
|
+
Sequel::SQL::ColumnAll.new(:a),
|
|
18
|
+
Sequel::SQL::ComplexExpression.new(:'=', :b, :a),
|
|
19
|
+
Sequel::SQL::Constant.new(:a),
|
|
20
|
+
Sequel::SQL::Function.new(:a, :b, :c),
|
|
21
|
+
Sequel::SQL::Identifier.new(:a),
|
|
22
|
+
Sequel::SQL::JoinClause.new(:inner, :b, :c),
|
|
23
|
+
Sequel::SQL::JoinOnClause.new({:d=>:a}, :inner, :b, :c),
|
|
24
|
+
Sequel::SQL::JoinUsingClause.new([:a], :inner, :b, :c),
|
|
25
|
+
Sequel::SQL::PlaceholderLiteralString.new('? = ?', [:a, :b]),
|
|
26
|
+
Sequel::SQL::PlaceholderLiteralString.new(':a = :b', [{:a=>:b, :b=>42}]),
|
|
27
|
+
Sequel::SQL::OrderedExpression.new(:a),
|
|
28
|
+
Sequel::SQL::OrderedExpression.new(:a, false),
|
|
29
|
+
Sequel::SQL::OrderedExpression.new(:a, false, :nulls=>:first),
|
|
30
|
+
Sequel::SQL::OrderedExpression.new(:a, false, :nulls=>:last),
|
|
31
|
+
Sequel::SQL::QualifiedIdentifier.new(:b, :a),
|
|
32
|
+
Sequel::SQL::Subscript.new(:a, [1, 2]),
|
|
33
|
+
Sequel::SQL::Window.new(:order=>:a, :partition=>:b),
|
|
34
|
+
Sequel::SQL::WindowFunction.new(Sequel::SQL::Function.new(:a, :b, :c), Sequel::SQL::Window.new(:order=>:a, :partition=>:b)),
|
|
35
|
+
Sequel::SQL::Wrapper.new(:a),
|
|
36
|
+
|
|
37
|
+
# Objects with components where eval(inspect) != self
|
|
38
|
+
Sequel::SQL::AliasedExpression.new(Sequel::SQL::Blob.new('s'), :a),
|
|
39
|
+
Sequel::SQL::AliasedExpression.new(Sequel::LiteralString.new('s'), :a),
|
|
40
|
+
Sequel::SQL::PlaceholderLiteralString.new('(a, b) IN ?', [Sequel::SQL::ValueList.new([[1, 2]])]),
|
|
41
|
+
Sequel::SQL::CaseExpression.new({{:d=>Sequel::LiteralString.new('e')}=>:a}, :c, :d),
|
|
42
|
+
Sequel::SQL::AliasedExpression.new(Date.new(2011, 10, 11), :a),
|
|
43
|
+
Sequel::SQL::AliasedExpression.new(Sequel::SQLTime.create(10, 20, 30, 500000.125), :a),
|
|
44
|
+
Sequel::SQL::AliasedExpression.new(DateTime.new(2011, 9, 11, 10, 20, 30), :a),
|
|
45
|
+
Sequel::SQL::AliasedExpression.new(DateTime.new(2011, 9, 11, 10, 20, 30, 0.25), :a),
|
|
46
|
+
Sequel::SQL::AliasedExpression.new(DateTime.new(2011, 9, 11, 10, 20, 30, -0.25), :a),
|
|
47
|
+
Sequel::SQL::AliasedExpression.new(Time.local(2011, 9, 11, 10, 20, 30), :a),
|
|
48
|
+
Sequel::SQL::AliasedExpression.new(Time.local(2011, 9, 11, 10, 20, 30, 500000.125), :a),
|
|
49
|
+
Sequel::SQL::AliasedExpression.new(Time.utc(2011, 9, 11, 10, 20, 30), :a),
|
|
50
|
+
Sequel::SQL::AliasedExpression.new(Time.utc(2011, 9, 11, 10, 20, 30, 500000.125), :a),
|
|
51
|
+
Sequel::SQL::AliasedExpression.new(BigDecimal.new('1.000000000000000000000000000000000000000000000001'), :a),
|
|
52
|
+
].each do |o|
|
|
53
|
+
v = eval(o.inspect)
|
|
54
|
+
v.should == o
|
|
55
|
+
@ds.literal(v).should == @ds.literal(o)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
|
2
2
|
|
|
3
|
-
begin
|
|
4
|
-
require 'json'
|
|
5
|
-
rescue LoadError => e
|
|
6
|
-
skip_warn "json_serializer plugin: can't load json (#{e.class}: #{e})"
|
|
7
|
-
else
|
|
8
3
|
describe "Sequel::Plugins::JsonSerializer" do
|
|
9
4
|
before do
|
|
10
5
|
class ::Artist < Sequel::Model
|
|
@@ -205,4 +200,3 @@ describe "Sequel::Plugins::JsonSerializer" do
|
|
|
205
200
|
Object.send(:remove_const, :Artist3)
|
|
206
201
|
end
|
|
207
202
|
end
|
|
208
|
-
end
|
|
@@ -4,18 +4,18 @@ describe "LooserTypecasting Extension" do
|
|
|
4
4
|
before do
|
|
5
5
|
@db = Sequel::Database.new({})
|
|
6
6
|
def @db.schema(*args)
|
|
7
|
-
[[:id, {}], [:
|
|
7
|
+
[[:id, {}], [:z, {:type=>:float}], [:b, {:type=>:integer}]]
|
|
8
8
|
end
|
|
9
9
|
@c = Class.new(Sequel::Model(@db[:items]))
|
|
10
10
|
@c.instance_eval do
|
|
11
|
-
@columns = [:id, :b, :
|
|
11
|
+
@columns = [:id, :b, :z]
|
|
12
12
|
def columns; @columns; end
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
specify "Should use to_i instead of Integer() for typecasting integers" do
|
|
17
17
|
proc{@c.new(:b=>'a')}.should raise_error(Sequel::InvalidValue)
|
|
18
|
-
@db.
|
|
18
|
+
@db.extension(:looser_typecasting)
|
|
19
19
|
@c.new(:b=>'a').b.should == 0
|
|
20
20
|
|
|
21
21
|
o = Object.new
|
|
@@ -26,14 +26,14 @@ describe "LooserTypecasting Extension" do
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
specify "Should use to_f instead of Float() for typecasting floats" do
|
|
29
|
-
proc{@c.new(:
|
|
30
|
-
@db.
|
|
31
|
-
@c.new(:
|
|
29
|
+
proc{@c.new(:z=>'a')}.should raise_error(Sequel::InvalidValue)
|
|
30
|
+
@db.extension(:looser_typecasting)
|
|
31
|
+
@c.new(:z=>'a').z.should == 0.0
|
|
32
32
|
|
|
33
33
|
o = Object.new
|
|
34
34
|
def o.to_f
|
|
35
35
|
1.0
|
|
36
36
|
end
|
|
37
|
-
@c.new(:
|
|
37
|
+
@c.new(:z=>o).z.should == 1.0
|
|
38
38
|
end
|
|
39
39
|
end
|
|
@@ -21,6 +21,41 @@ describe Sequel::Model, "many_through_many" do
|
|
|
21
21
|
Object.send(:remove_const, :Tag)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
|
+
it "should populate :key_hash and :id_map option correctly for custom eager loaders" do
|
|
25
|
+
khs = []
|
|
26
|
+
pr = proc{|h| khs << [h[:key_hash], h[:id_map]]}
|
|
27
|
+
@c1.many_through_many :tags, :through=>[[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :eager_loader=>pr
|
|
28
|
+
@c1.eager(:tags).all
|
|
29
|
+
khs.should == [[{:id=>{1=>[Artist.load(:x=>1, :id=>1)]}}, {1=>[Artist.load(:x=>1, :id=>1)]}]]
|
|
30
|
+
|
|
31
|
+
khs.clear
|
|
32
|
+
@c1.many_through_many :tags, :through=>[[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :left_primary_key=>:id, :left_primary_key_column=>:i, :eager_loader=>pr
|
|
33
|
+
@c1.eager(:tags).all
|
|
34
|
+
khs.should == [[{:id=>{1=>[Artist.load(:x=>1, :id=>1)]}}, {1=>[Artist.load(:x=>1, :id=>1)]}]]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "should support using a custom :left_primary_key option when eager loading many_to_many associations" do
|
|
38
|
+
@c1.send(:define_method, :id3){id*3}
|
|
39
|
+
@c1.dataset._fetch = {:id=>1}
|
|
40
|
+
@c2.dataset._fetch = {:id=>4, :x_foreign_key_x=>3}
|
|
41
|
+
@c1.many_through_many :tags, :through=>[[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :left_primary_key=>:id3
|
|
42
|
+
a = @c1.eager(:tags).all
|
|
43
|
+
a.should == [@c1.load(:id => 1)]
|
|
44
|
+
MODEL_DB.sqls.should == ['SELECT * FROM artists', "SELECT tags.*, albums_artists.artist_id AS x_foreign_key_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND (albums_artists.artist_id IN (3)))"]
|
|
45
|
+
a.first.tags.should == [@c2.load(:id=>4)]
|
|
46
|
+
MODEL_DB.sqls.should == []
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "should handle a :eager_loading_predicate_key option to change the SQL used in the lookup" do
|
|
50
|
+
@c1.dataset._fetch = {:id=>1}
|
|
51
|
+
@c2.dataset._fetch = {:id=>4, :x_foreign_key_x=>1}
|
|
52
|
+
@c1.many_through_many :tags, :through=>[[:albums_artists, :artist_id, :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :eager_loading_predicate_key=>Sequel./(:albums_artists__artist_id, 3)
|
|
53
|
+
a = @c1.eager(:tags).all
|
|
54
|
+
a.should == [@c1.load(:id => 1)]
|
|
55
|
+
MODEL_DB.sqls.should == ['SELECT * FROM artists', "SELECT tags.*, (albums_artists.artist_id / 3) AS x_foreign_key_x FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) INNER JOIN albums_artists ON ((albums_artists.album_id = albums.id) AND ((albums_artists.artist_id / 3) IN (1)))"]
|
|
56
|
+
a.first.tags.should == [@c2.load(:id=>4)]
|
|
57
|
+
end
|
|
58
|
+
|
|
24
59
|
it "should default to associating to other models in the same scope" do
|
|
25
60
|
begin
|
|
26
61
|
class ::AssociationModuleTest
|
|
@@ -598,6 +633,7 @@ describe "Sequel::Plugins::ManyThroughMany eager loading methods" do
|
|
|
598
633
|
it "should respect the :limit option on a many_through_many association with composite primary keys on the main table using a :window_function strategy" do
|
|
599
634
|
Tag.dataset.meta_def(:supports_window_functions?){true}
|
|
600
635
|
@c1.set_primary_key([:id1, :id2])
|
|
636
|
+
@c1.columns :id1, :id2
|
|
601
637
|
@c1.many_through_many :first_two_tags, [[:albums_artists, [:artist_id1, :artist_id2], :album_id], [:albums, :id, :id], [:albums_tags, :album_id, :tag_id]], :class=>Tag, :limit=>2, :eager_limit_strategy=>true, :order=>:name
|
|
602
638
|
@c1.dataset._fetch = [{:id1=>1, :id2=>2}]
|
|
603
639
|
Tag.dataset._fetch = [{:x_foreign_key_0_x=>1, :x_foreign_key_1_x=>2, :id=>5}, {:x_foreign_key_0_x=>1, :x_foreign_key_1_x=>2, :id=>6}]
|
|
@@ -934,3 +970,48 @@ describe "Sequel::Plugins::ManyThroughMany eager loading methods" do
|
|
|
934
970
|
@c1.eager_graph(:tags, :albums).sql.should == 'SELECT artists.id, tags.id AS tags_id, albums_0.id AS albums_0_id FROM artists LEFT OUTER JOIN albums_artists ON ((albums_artists.artist_id = artists.id) AND (albums_artists.a = artists.b)) LEFT OUTER JOIN albums ON (albums.id = albums_artists.album_id) LEFT OUTER JOIN albums_tags ON (albums_tags.album_id = albums.id) LEFT OUTER JOIN tags ON (tags.id = albums_tags.tag_id) LEFT OUTER JOIN albums_artists AS albums_artists_0 ON ((albums_artists_0.artist_id = artists.id) AND (albums_artists_0.c = artists.d)) LEFT OUTER JOIN albums AS albums_0 ON (albums_0.id = albums_artists_0.album_id)'
|
|
935
971
|
end
|
|
936
972
|
end
|
|
973
|
+
|
|
974
|
+
describe "many_through_many associations with non-column expression keys" do
|
|
975
|
+
before do
|
|
976
|
+
@db = Sequel.mock(:fetch=>{:id=>1, :object_ids=>[2]})
|
|
977
|
+
@Foo = Class.new(Sequel::Model(@db[:foos]))
|
|
978
|
+
@Foo.columns :id, :object_ids
|
|
979
|
+
@Foo.plugin :many_through_many
|
|
980
|
+
m = Module.new{def obj_id; object_ids[0]; end}
|
|
981
|
+
@Foo.include m
|
|
982
|
+
|
|
983
|
+
@Foo.many_through_many :foos, [
|
|
984
|
+
[:f, Sequel.subscript(:l, 0), Sequel.subscript(:r, 0)],
|
|
985
|
+
[:f, Sequel.subscript(:l, 1), Sequel.subscript(:r, 1)]
|
|
986
|
+
], :class=>@Foo, :left_primary_key=>:obj_id, :left_primary_key_column=>Sequel.subscript(:object_ids, 0), :right_primary_key=>Sequel.subscript(:object_ids, 0), :right_primary_key_method=>:obj_id
|
|
987
|
+
@foo = @Foo.load(:id=>1, :object_ids=>[2])
|
|
988
|
+
@db.sqls
|
|
989
|
+
end
|
|
990
|
+
|
|
991
|
+
it "should have working regular association methods" do
|
|
992
|
+
@Foo.first.foos.should == [@foo]
|
|
993
|
+
@db.sqls.should == ["SELECT * FROM foos LIMIT 1", "SELECT foos.* FROM foos INNER JOIN f ON (f.r[1] = foos.object_ids[0]) INNER JOIN f AS f_0 ON ((f_0.r[0] = f.l[1]) AND (f_0.l[0] = 2))"]
|
|
994
|
+
end
|
|
995
|
+
|
|
996
|
+
it "should have working eager loading methods" do
|
|
997
|
+
@db.fetch = [[{:id=>1, :object_ids=>[2]}], [{:id=>1, :object_ids=>[2], :x_foreign_key_x=>2}]]
|
|
998
|
+
@Foo.eager(:foos).all.map{|o| [o, o.foos]}.should == [[@foo, [@foo]]]
|
|
999
|
+
@db.sqls.should == ["SELECT * FROM foos", "SELECT foos.*, f_0.l[0] AS x_foreign_key_x FROM foos INNER JOIN f ON (f.r[1] = foos.object_ids[0]) INNER JOIN f AS f_0 ON ((f_0.r[0] = f.l[1]) AND (f_0.l[0] IN (2)))"]
|
|
1000
|
+
end
|
|
1001
|
+
|
|
1002
|
+
it "should have working eager graphing methods" do
|
|
1003
|
+
@db.fetch = {:id=>1, :object_ids=>[2], :foos_0_id=>1, :foos_0_object_ids=>[2]}
|
|
1004
|
+
@Foo.eager_graph(:foos).all.map{|o| [o, o.foos]}.should == [[@foo, [@foo]]]
|
|
1005
|
+
@db.sqls.should == ["SELECT foos.id, foos.object_ids, foos_0.id AS foos_0_id, foos_0.object_ids AS foos_0_object_ids FROM foos LEFT OUTER JOIN f ON (f.l[0] = foos.object_ids[0]) LEFT OUTER JOIN f AS f_0 ON (f_0.l[1] = f.r[0]) LEFT OUTER JOIN foos AS foos_0 ON (foos_0.object_ids[0] = f_0.r[1])"]
|
|
1006
|
+
end
|
|
1007
|
+
|
|
1008
|
+
it "should have working filter by associations with model instances" do
|
|
1009
|
+
@Foo.first(:foos=>@foo).should == @foo
|
|
1010
|
+
@db.sqls.should == ["SELECT * FROM foos WHERE (foos.object_ids[0] IN (SELECT f.l[0] FROM f INNER JOIN f AS f_0 ON (f_0.l[1] = f.r[0]) WHERE ((f_0.r[1] = 2) AND (f.l[0] IS NOT NULL)))) LIMIT 1"]
|
|
1011
|
+
end
|
|
1012
|
+
|
|
1013
|
+
it "should have working filter by associations with model datasets" do
|
|
1014
|
+
@Foo.first(:foos=>@Foo.where(:id=>@foo.id)).should == @foo
|
|
1015
|
+
@db.sqls.should == ["SELECT * FROM foos WHERE (foos.object_ids[0] IN (SELECT f.l[0] FROM f INNER JOIN f AS f_0 ON (f_0.l[1] = f.r[0]) WHERE ((f_0.r[1] IN (SELECT foos.object_ids[0] FROM foos WHERE ((id = 1) AND (foos.object_ids[0] IS NOT NULL)))) AND (f.l[0] IS NOT NULL)))) LIMIT 1"]
|
|
1016
|
+
end
|
|
1017
|
+
end
|