sequel 3.21.0 → 3.36.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 +855 -3
- data/MIT-LICENSE +1 -1
- data/README.rdoc +23 -7
- data/Rakefile +42 -24
- data/bin/sequel +26 -8
- data/doc/active_record.rdoc +1 -0
- data/doc/advanced_associations.rdoc +171 -11
- data/doc/association_basics.rdoc +293 -43
- data/doc/dataset_basics.rdoc +5 -5
- data/doc/dataset_filtering.rdoc +8 -0
- data/doc/mass_assignment.rdoc +56 -0
- data/doc/migration.rdoc +85 -552
- data/doc/model_hooks.rdoc +78 -27
- data/doc/object_model.rdoc +541 -0
- data/doc/opening_databases.rdoc +97 -50
- data/doc/prepared_statements.rdoc +40 -14
- data/doc/querying.rdoc +28 -4
- data/doc/reflection.rdoc +30 -4
- data/doc/release_notes/3.22.0.txt +39 -0
- data/doc/release_notes/3.23.0.txt +172 -0
- data/doc/release_notes/3.24.0.txt +420 -0
- data/doc/release_notes/3.25.0.txt +88 -0
- data/doc/release_notes/3.26.0.txt +88 -0
- data/doc/release_notes/3.27.0.txt +82 -0
- data/doc/release_notes/3.28.0.txt +304 -0
- data/doc/release_notes/3.29.0.txt +459 -0
- data/doc/release_notes/3.30.0.txt +135 -0
- data/doc/release_notes/3.31.0.txt +146 -0
- data/doc/release_notes/3.32.0.txt +202 -0
- data/doc/release_notes/3.33.0.txt +157 -0
- data/doc/release_notes/3.34.0.txt +671 -0
- data/doc/release_notes/3.35.0.txt +144 -0
- data/doc/release_notes/3.36.0.txt +245 -0
- data/doc/schema_modification.rdoc +572 -0
- data/doc/sharding.rdoc +95 -3
- data/doc/testing.rdoc +129 -0
- data/doc/thread_safety.rdoc +17 -0
- data/doc/transactions.rdoc +137 -0
- data/doc/virtual_rows.rdoc +51 -2
- data/lib/sequel/adapters/ado/mssql.rb +18 -6
- data/lib/sequel/adapters/ado.rb +40 -18
- data/lib/sequel/adapters/amalgalite.rb +17 -9
- data/lib/sequel/adapters/db2.rb +175 -86
- data/lib/sequel/adapters/dbi.rb +15 -15
- data/lib/sequel/adapters/do/mysql.rb +17 -11
- data/lib/sequel/adapters/do/postgres.rb +1 -57
- data/lib/sequel/adapters/do/sqlite.rb +0 -10
- data/lib/sequel/adapters/do.rb +18 -36
- data/lib/sequel/adapters/firebird.rb +27 -208
- data/lib/sequel/adapters/ibmdb.rb +453 -0
- data/lib/sequel/adapters/informix.rb +6 -23
- data/lib/sequel/adapters/jdbc/as400.rb +16 -34
- data/lib/sequel/adapters/jdbc/db2.rb +47 -0
- data/lib/sequel/adapters/jdbc/derby.rb +287 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +24 -0
- data/lib/sequel/adapters/jdbc/h2.rb +73 -31
- data/lib/sequel/adapters/jdbc/hsqldb.rb +184 -0
- data/lib/sequel/adapters/jdbc/informix.rb +21 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +29 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
- data/lib/sequel/adapters/jdbc/mysql.rb +7 -24
- data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
- data/lib/sequel/adapters/jdbc/postgresql.rb +58 -48
- data/lib/sequel/adapters/jdbc/progress.rb +21 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +20 -10
- data/lib/sequel/adapters/jdbc/sqlserver.rb +66 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
- data/lib/sequel/adapters/jdbc.rb +265 -94
- data/lib/sequel/adapters/mock.rb +361 -0
- data/lib/sequel/adapters/mysql.rb +118 -222
- data/lib/sequel/adapters/mysql2.rb +58 -57
- data/lib/sequel/adapters/odbc/mssql.rb +15 -7
- data/lib/sequel/adapters/odbc.rb +28 -9
- data/lib/sequel/adapters/openbase.rb +3 -5
- data/lib/sequel/adapters/oracle.rb +349 -53
- data/lib/sequel/adapters/postgres.rb +356 -107
- data/lib/sequel/adapters/shared/access.rb +32 -9
- data/lib/sequel/adapters/shared/db2.rb +342 -0
- data/lib/sequel/adapters/shared/firebird.rb +221 -0
- data/lib/sequel/adapters/shared/informix.rb +53 -0
- data/lib/sequel/adapters/shared/mssql.rb +335 -118
- data/lib/sequel/adapters/shared/mysql.rb +340 -76
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +155 -0
- data/lib/sequel/adapters/shared/oracle.rb +243 -45
- data/lib/sequel/adapters/shared/postgres.rb +524 -279
- data/lib/sequel/adapters/shared/progress.rb +5 -8
- data/lib/sequel/adapters/shared/sqlite.rb +265 -89
- data/lib/sequel/adapters/sqlite.rb +101 -39
- data/lib/sequel/adapters/swift/mysql.rb +9 -12
- data/lib/sequel/adapters/swift/postgres.rb +9 -74
- data/lib/sequel/adapters/swift/sqlite.rb +8 -6
- data/lib/sequel/adapters/swift.rb +8 -7
- data/lib/sequel/adapters/tinytds.rb +161 -21
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +66 -0
- data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
- data/lib/sequel/ast_transformer.rb +194 -0
- data/lib/sequel/connection_pool/sharded_single.rb +11 -1
- data/lib/sequel/connection_pool/sharded_threaded.rb +28 -2
- data/lib/sequel/connection_pool/single.rb +5 -0
- data/lib/sequel/connection_pool/threaded.rb +38 -14
- data/lib/sequel/connection_pool.rb +10 -2
- data/lib/sequel/core.rb +118 -11
- data/lib/sequel/database/connecting.rb +38 -28
- data/lib/sequel/database/dataset.rb +4 -4
- data/lib/sequel/database/dataset_defaults.rb +63 -2
- data/lib/sequel/database/logging.rb +7 -2
- data/lib/sequel/database/misc.rb +150 -46
- data/lib/sequel/database/query.rb +215 -65
- data/lib/sequel/database/schema_generator.rb +64 -20
- data/lib/sequel/database/schema_methods.rb +212 -54
- data/lib/sequel/dataset/actions.rb +322 -85
- data/lib/sequel/dataset/features.rb +96 -8
- data/lib/sequel/dataset/graph.rb +38 -11
- data/lib/sequel/dataset/misc.rb +50 -23
- data/lib/sequel/dataset/mutation.rb +12 -7
- data/lib/sequel/dataset/prepared_statements.rb +68 -30
- data/lib/sequel/dataset/query.rb +237 -44
- data/lib/sequel/dataset/sql.rb +698 -278
- data/lib/sequel/dataset.rb +8 -0
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/_pretty_table.rb +79 -0
- data/lib/sequel/extensions/arbitrary_servers.rb +108 -0
- data/lib/sequel/extensions/columns_introspection.rb +61 -0
- data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +16 -34
- data/lib/sequel/extensions/migration.rb +97 -11
- data/lib/sequel/extensions/named_timezones.rb +5 -0
- data/lib/sequel/extensions/null_dataset.rb +90 -0
- data/lib/sequel/extensions/pg_array.rb +460 -0
- data/lib/sequel/extensions/pg_array_ops.rb +220 -0
- data/lib/sequel/extensions/pg_auto_parameterize.rb +169 -0
- data/lib/sequel/extensions/pg_hstore.rb +296 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +259 -0
- data/lib/sequel/extensions/pg_inet.rb +89 -0
- data/lib/sequel/extensions/pg_json.rb +178 -0
- data/lib/sequel/extensions/pg_statement_cache.rb +316 -0
- data/lib/sequel/extensions/pretty_table.rb +5 -71
- data/lib/sequel/extensions/query.rb +1 -1
- data/lib/sequel/extensions/query_literals.rb +79 -0
- data/lib/sequel/extensions/schema_caching.rb +76 -0
- data/lib/sequel/extensions/schema_dumper.rb +251 -37
- data/lib/sequel/extensions/select_remove.rb +35 -0
- data/lib/sequel/extensions/server_block.rb +139 -0
- data/lib/sequel/extensions/sql_expr.rb +4 -110
- data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
- data/lib/sequel/extensions/to_dot.rb +95 -83
- data/lib/sequel/model/associations.rb +1187 -393
- data/lib/sequel/model/base.rb +578 -170
- data/lib/sequel/model/errors.rb +1 -1
- data/lib/sequel/model/exceptions.rb +5 -1
- data/lib/sequel/model/inflections.rb +1 -1
- data/lib/sequel/model.rb +30 -11
- data/lib/sequel/no_core_ext.rb +2 -0
- data/lib/sequel/plugins/active_model.rb +13 -1
- data/lib/sequel/plugins/association_pks.rb +22 -4
- data/lib/sequel/plugins/caching.rb +25 -18
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/composition.rb +44 -12
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/defaults_setter.rb +58 -0
- data/lib/sequel/plugins/dirty.rb +214 -0
- data/lib/sequel/plugins/eager_each.rb +59 -0
- data/lib/sequel/plugins/force_encoding.rb +6 -6
- data/lib/sequel/plugins/hook_class_methods.rb +1 -1
- data/lib/sequel/plugins/identity_map.rb +123 -8
- data/lib/sequel/plugins/instance_filters.rb +10 -0
- data/lib/sequel/plugins/instance_hooks.rb +1 -1
- data/lib/sequel/plugins/json_serializer.rb +58 -6
- data/lib/sequel/plugins/list.rb +12 -2
- data/lib/sequel/plugins/many_through_many.rb +79 -28
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
- data/lib/sequel/plugins/nested_attributes.rb +139 -63
- data/lib/sequel/plugins/optimistic_locking.rb +8 -0
- data/lib/sequel/plugins/prepared_statements.rb +167 -0
- data/lib/sequel/plugins/prepared_statements_associations.rb +87 -0
- data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
- data/lib/sequel/plugins/rcte_tree.rb +29 -15
- data/lib/sequel/plugins/schema.rb +7 -2
- data/lib/sequel/plugins/serialization.rb +98 -49
- data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
- data/lib/sequel/plugins/sharding.rb +21 -54
- data/lib/sequel/plugins/single_table_inheritance.rb +5 -3
- data/lib/sequel/plugins/static_cache.rb +99 -0
- data/lib/sequel/plugins/subclasses.rb +10 -2
- data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
- data/lib/sequel/plugins/timestamps.rb +1 -1
- data/lib/sequel/plugins/typecast_on_load.rb +9 -12
- data/lib/sequel/plugins/update_primary_key.rb +2 -2
- data/lib/sequel/plugins/validation_class_methods.rb +1 -1
- data/lib/sequel/plugins/xml_serializer.rb +15 -4
- data/lib/sequel/sql.rb +526 -59
- data/lib/sequel/timezones.rb +57 -38
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +146 -0
- data/spec/adapters/firebird_spec.rb +1 -1
- data/spec/adapters/mssql_spec.rb +142 -40
- data/spec/adapters/mysql_spec.rb +380 -234
- data/spec/adapters/oracle_spec.rb +67 -77
- data/spec/adapters/postgres_spec.rb +1050 -212
- data/spec/adapters/spec_helper.rb +8 -5
- data/spec/adapters/sqlite_spec.rb +139 -27
- data/spec/core/connection_pool_spec.rb +196 -93
- data/spec/core/database_spec.rb +879 -510
- data/spec/core/dataset_spec.rb +1415 -1086
- data/spec/core/expression_filters_spec.rb +554 -109
- data/spec/core/mock_adapter_spec.rb +449 -0
- data/spec/core/object_graph_spec.rb +86 -114
- data/spec/core/schema_generator_spec.rb +4 -4
- data/spec/core/schema_spec.rb +482 -38
- data/spec/core/spec_helper.rb +6 -48
- data/spec/extensions/active_model_spec.rb +13 -0
- data/spec/extensions/arbitrary_servers_spec.rb +110 -0
- data/spec/extensions/association_autoreloading_spec.rb +18 -10
- data/spec/extensions/association_dependencies_spec.rb +15 -25
- data/spec/extensions/association_pks_spec.rb +66 -32
- data/spec/extensions/association_proxies_spec.rb +4 -4
- data/spec/extensions/caching_spec.rb +47 -51
- data/spec/extensions/class_table_inheritance_spec.rb +31 -83
- data/spec/extensions/columns_introspection_spec.rb +91 -0
- data/spec/extensions/composition_spec.rb +18 -13
- data/spec/{core/core_sql_spec.rb → extensions/core_extensions_spec.rb} +119 -139
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/defaults_setter_spec.rb +64 -0
- data/spec/extensions/dirty_spec.rb +155 -0
- data/spec/extensions/eager_each_spec.rb +34 -0
- data/spec/extensions/force_encoding_spec.rb +4 -2
- data/spec/extensions/hook_class_methods_spec.rb +69 -92
- data/spec/extensions/identity_map_spec.rb +131 -22
- data/spec/extensions/inflector_spec.rb +0 -4
- data/spec/extensions/instance_filters_spec.rb +11 -21
- data/spec/extensions/instance_hooks_spec.rb +72 -0
- data/spec/extensions/json_serializer_spec.rb +49 -6
- data/spec/extensions/lazy_attributes_spec.rb +16 -20
- data/spec/extensions/list_spec.rb +48 -39
- data/spec/extensions/many_through_many_spec.rb +283 -250
- data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
- data/spec/extensions/migration_spec.rb +140 -35
- data/spec/extensions/named_timezones_spec.rb +29 -11
- data/spec/extensions/nested_attributes_spec.rb +251 -89
- data/spec/extensions/null_dataset_spec.rb +85 -0
- data/spec/extensions/optimistic_locking_spec.rb +24 -21
- data/spec/extensions/pg_array_ops_spec.rb +105 -0
- data/spec/extensions/pg_array_spec.rb +196 -0
- data/spec/extensions/pg_auto_parameterize_spec.rb +65 -0
- data/spec/extensions/pg_hstore_ops_spec.rb +136 -0
- data/spec/extensions/pg_hstore_spec.rb +195 -0
- data/spec/extensions/pg_inet_spec.rb +44 -0
- data/spec/extensions/pg_json_spec.rb +101 -0
- data/spec/extensions/pg_statement_cache_spec.rb +209 -0
- data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
- data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
- data/spec/extensions/prepared_statements_spec.rb +87 -0
- data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
- data/spec/extensions/pretty_table_spec.rb +7 -6
- data/spec/extensions/query_literals_spec.rb +168 -0
- data/spec/extensions/query_spec.rb +6 -0
- data/spec/extensions/rcte_tree_spec.rb +50 -43
- data/spec/extensions/schema_caching_spec.rb +41 -0
- data/spec/extensions/schema_dumper_spec.rb +429 -22
- data/spec/extensions/schema_spec.rb +25 -21
- data/spec/extensions/select_remove_spec.rb +38 -0
- data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
- data/spec/extensions/serialization_spec.rb +85 -43
- data/spec/extensions/server_block_spec.rb +90 -0
- data/spec/extensions/sharding_spec.rb +69 -143
- data/spec/extensions/single_table_inheritance_spec.rb +23 -29
- data/spec/extensions/skip_create_refresh_spec.rb +1 -1
- data/spec/extensions/spec_helper.rb +22 -61
- data/spec/extensions/sql_expr_spec.rb +29 -60
- data/spec/extensions/static_cache_spec.rb +145 -0
- data/spec/extensions/tactical_eager_loading_spec.rb +17 -19
- data/spec/extensions/thread_local_timezones_spec.rb +22 -2
- data/spec/extensions/timestamps_spec.rb +6 -6
- data/spec/extensions/to_dot_spec.rb +4 -7
- data/spec/extensions/touch_spec.rb +13 -14
- data/spec/extensions/tree_spec.rb +11 -26
- data/spec/extensions/typecast_on_load_spec.rb +9 -6
- data/spec/extensions/update_primary_key_spec.rb +30 -24
- data/spec/extensions/validation_class_methods_spec.rb +30 -51
- data/spec/extensions/validation_helpers_spec.rb +16 -35
- data/spec/extensions/xml_serializer_spec.rb +29 -4
- data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +4 -0
- data/spec/files/transaction_specified_migrations/002_create_basic.rb +4 -0
- data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +3 -0
- data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +3 -0
- data/spec/integration/associations_test.rb +659 -21
- data/spec/integration/database_test.rb +9 -3
- data/spec/integration/dataset_test.rb +605 -91
- data/spec/integration/eager_loader_test.rb +19 -21
- data/spec/integration/migrator_test.rb +2 -3
- data/spec/integration/model_test.rb +81 -2
- data/spec/integration/plugin_test.rb +454 -143
- data/spec/integration/prepared_statement_test.rb +263 -128
- data/spec/integration/schema_test.rb +309 -43
- data/spec/integration/spec_helper.rb +40 -30
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +183 -8
- data/spec/integration/type_test.rb +18 -4
- data/spec/model/association_reflection_spec.rb +201 -7
- data/spec/model/associations_spec.rb +1067 -661
- data/spec/model/base_spec.rb +329 -95
- data/spec/model/dataset_methods_spec.rb +7 -27
- data/spec/model/eager_loading_spec.rb +677 -676
- data/spec/model/hooks_spec.rb +349 -67
- data/spec/model/model_spec.rb +240 -168
- data/spec/model/plugins_spec.rb +24 -13
- data/spec/model/record_spec.rb +490 -232
- data/spec/model/spec_helper.rb +14 -71
- data/spec/model/validations_spec.rb +11 -0
- data/spec/rcov.opts +2 -0
- metadata +178 -80
|
@@ -1,28 +1,106 @@
|
|
|
1
1
|
require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
|
|
2
2
|
|
|
3
|
-
describe "
|
|
4
|
-
specify "should
|
|
5
|
-
[]
|
|
3
|
+
describe "Sequel core extensions" do
|
|
4
|
+
specify "should not be used inside Sequel, to insure Sequel works without them" do
|
|
5
|
+
usage = []
|
|
6
|
+
match_re = /(\.(sql_value_list|sql_array|sql_expr|sql_negate|sql_or|sql_string_join|lit|to_sequel_blob|case)\W)|:\w+\.(qualify|identifier|as|cast|asc|desc|sql_subscript|\*|sql_function)\W/
|
|
7
|
+
comment_re = /^\s*#|# core_sql/
|
|
8
|
+
Dir['lib/sequel/**/*.rb'].each do |f|
|
|
9
|
+
lines = File.read(f).split("\n").grep(match_re).delete_if{|l| l =~ comment_re}
|
|
10
|
+
usage << [f, lines] unless lines.empty?
|
|
11
|
+
end
|
|
12
|
+
puts usage unless usage.empty?
|
|
13
|
+
usage.should be_empty
|
|
6
14
|
end
|
|
7
15
|
|
|
8
|
-
specify "should
|
|
9
|
-
|
|
10
|
-
[[1,2],1].all_two_pairs?.should == false
|
|
16
|
+
specify "should have Sequel.core_extensions? be true if enabled" do
|
|
17
|
+
Sequel.core_extensions?.should be_true
|
|
11
18
|
end
|
|
19
|
+
end
|
|
12
20
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
[
|
|
21
|
+
describe "Array and Hash extensions" do
|
|
22
|
+
before do
|
|
23
|
+
db = Sequel::Database.new
|
|
24
|
+
@d = db[:items]
|
|
25
|
+
def @d.l(*args, &block)
|
|
26
|
+
literal(filter_expr(*args, &block))
|
|
27
|
+
end
|
|
28
|
+
def @d.lit(*args)
|
|
29
|
+
literal(*args)
|
|
30
|
+
end
|
|
17
31
|
end
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
[[
|
|
21
|
-
[[
|
|
22
|
-
[[
|
|
32
|
+
|
|
33
|
+
it "should support sql_expr on arrays with all two pairs" do
|
|
34
|
+
@d.l([[:x, 100],[:y, 'a']].sql_expr).should == '((x = 100) AND (y = \'a\'))'
|
|
35
|
+
@d.l([[:x, true], [:y, false]].sql_expr).should == '((x IS TRUE) AND (y IS FALSE))'
|
|
36
|
+
@d.l([[:x, nil], [:y, [1,2,3]]].sql_expr).should == '((x IS NULL) AND (y IN (1, 2, 3)))'
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "should support sql_negate on arrays with all two pairs" do
|
|
40
|
+
@d.l([[:x, 100],[:y, 'a']].sql_negate).should == '((x != 100) AND (y != \'a\'))'
|
|
41
|
+
@d.l([[:x, true], [:y, false]].sql_negate).should == '((x IS NOT TRUE) AND (y IS NOT FALSE))'
|
|
42
|
+
@d.l([[:x, nil], [:y, [1,2,3]]].sql_negate).should == '((x IS NOT NULL) AND (y NOT IN (1, 2, 3)))'
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "should support ~ on arrays with all two pairs" do
|
|
46
|
+
@d.l(~[[:x, 100],[:y, 'a']]).should == '((x != 100) OR (y != \'a\'))'
|
|
47
|
+
@d.l(~[[:x, true], [:y, false]]).should == '((x IS NOT TRUE) OR (y IS NOT FALSE))'
|
|
48
|
+
@d.l(~[[:x, nil], [:y, [1,2,3]]]).should == '((x IS NOT NULL) OR (y NOT IN (1, 2, 3)))'
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "should support sql_or on arrays with all two pairs" do
|
|
52
|
+
@d.l([[:x, 100],[:y, 'a']].sql_or).should == '((x = 100) OR (y = \'a\'))'
|
|
53
|
+
@d.l([[:x, true], [:y, false]].sql_or).should == '((x IS TRUE) OR (y IS FALSE))'
|
|
54
|
+
@d.l([[:x, nil], [:y, [1,2,3]]].sql_or).should == '((x IS NULL) OR (y IN (1, 2, 3)))'
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "should support Array#sql_string_join for concatenation of SQL strings" do
|
|
58
|
+
@d.lit([:x].sql_string_join).should == '(x)'
|
|
59
|
+
@d.lit([:x].sql_string_join(', ')).should == '(x)'
|
|
60
|
+
@d.lit([:x, :y].sql_string_join).should == '(x || y)'
|
|
61
|
+
@d.lit([:x, :y].sql_string_join(', ')).should == "(x || ', ' || y)"
|
|
62
|
+
@d.lit([:x.sql_function(1), :y.sql_subscript(1)].sql_string_join).should == '(x(1) || y[1])'
|
|
63
|
+
@d.lit([:x.sql_function(1), 'y.z'.lit].sql_string_join(', ')).should == "(x(1) || ', ' || y.z)"
|
|
64
|
+
@d.lit([:x, 1, :y].sql_string_join).should == "(x || '1' || y)"
|
|
65
|
+
@d.lit([:x, 1, :y].sql_string_join(', ')).should == "(x || ', ' || '1' || ', ' || y)"
|
|
66
|
+
@d.lit([:x, 1, :y].sql_string_join(:y__z)).should == "(x || y.z || '1' || y.z || y)"
|
|
67
|
+
@d.lit([:x, 1, :y].sql_string_join(1)).should == "(x || '1' || '1' || '1' || y)"
|
|
68
|
+
@d.lit([:x, :y].sql_string_join('y.x || x.y'.lit)).should == "(x || y.x || x.y || y)"
|
|
69
|
+
@d.lit([[:x, :y].sql_string_join, [:a, :b].sql_string_join].sql_string_join).should == "(x || y || a || b)"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "should support sql_expr on hashes" do
|
|
73
|
+
@d.l({:x => 100, :y => 'a'}.sql_expr)[1...-1].split(' AND ').sort.should == ['(x = 100)', '(y = \'a\')']
|
|
74
|
+
@d.l({:x => true, :y => false}.sql_expr)[1...-1].split(' AND ').sort.should == ['(x IS TRUE)', '(y IS FALSE)']
|
|
75
|
+
@d.l({:x => nil, :y => [1,2,3]}.sql_expr)[1...-1].split(' AND ').sort.should == ['(x IS NULL)', '(y IN (1, 2, 3))']
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it "should support sql_negate on hashes" do
|
|
79
|
+
@d.l({:x => 100, :y => 'a'}.sql_negate)[1...-1].split(' AND ').sort.should == ['(x != 100)', '(y != \'a\')']
|
|
80
|
+
@d.l({:x => true, :y => false}.sql_negate)[1...-1].split(' AND ').sort.should == ['(x IS NOT TRUE)', '(y IS NOT FALSE)']
|
|
81
|
+
@d.l({:x => nil, :y => [1,2,3]}.sql_negate)[1...-1].split(' AND ').sort.should == ['(x IS NOT NULL)', '(y NOT IN (1, 2, 3))']
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it "should support ~ on hashes" do
|
|
85
|
+
@d.l(~{:x => 100, :y => 'a'})[1...-1].split(' OR ').sort.should == ['(x != 100)', '(y != \'a\')']
|
|
86
|
+
@d.l(~{:x => true, :y => false})[1...-1].split(' OR ').sort.should == ['(x IS NOT TRUE)', '(y IS NOT FALSE)']
|
|
87
|
+
@d.l(~{:x => nil, :y => [1,2,3]})[1...-1].split(' OR ').sort.should == ['(x IS NOT NULL)', '(y NOT IN (1, 2, 3))']
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it "should support sql_or on hashes" do
|
|
91
|
+
@d.l({:x => 100, :y => 'a'}.sql_or)[1...-1].split(' OR ').sort.should == ['(x = 100)', '(y = \'a\')']
|
|
92
|
+
@d.l({:x => true, :y => false}.sql_or)[1...-1].split(' OR ').sort.should == ['(x IS TRUE)', '(y IS FALSE)']
|
|
93
|
+
@d.l({:x => nil, :y => [1,2,3]}.sql_or)[1...-1].split(' OR ').sort.should == ['(x IS NULL)', '(y IN (1, 2, 3))']
|
|
23
94
|
end
|
|
24
|
-
end
|
|
25
95
|
|
|
96
|
+
it "should Hash#& and Hash#|" do
|
|
97
|
+
@d.l({:y => :z} & :x).should == '((y = z) AND x)'
|
|
98
|
+
@d.l({:x => :a} & {:y => :z}).should == '((x = a) AND (y = z))'
|
|
99
|
+
@d.l({:y => :z} | :x).should == '((y = z) OR x)'
|
|
100
|
+
@d.l({:x => :a} | {:y => :z}).should == '((x = a) OR (y = z))'
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
26
104
|
describe "Array#case and Hash#case" do
|
|
27
105
|
before do
|
|
28
106
|
@d = Sequel::Dataset.new(nil)
|
|
@@ -75,16 +153,16 @@ end
|
|
|
75
153
|
|
|
76
154
|
describe "String#lit" do
|
|
77
155
|
before do
|
|
78
|
-
@ds = ds =
|
|
156
|
+
@ds = ds = Sequel::Database.new[:t]
|
|
79
157
|
end
|
|
158
|
+
|
|
80
159
|
specify "should return an LiteralString object" do
|
|
81
160
|
'xyz'.lit.should be_a_kind_of(Sequel::LiteralString)
|
|
82
161
|
'xyz'.lit.to_s.should == 'xyz'
|
|
83
162
|
end
|
|
84
163
|
|
|
85
164
|
specify "should inhibit string literalization" do
|
|
86
|
-
|
|
87
|
-
"UPDATE t SET stamp = NOW()"
|
|
165
|
+
@ds.update_sql(:stamp => "NOW()".lit).should == "UPDATE t SET stamp = NOW()"
|
|
88
166
|
end
|
|
89
167
|
|
|
90
168
|
specify "should return a PlaceholderLiteralString object if args are given" do
|
|
@@ -176,10 +254,10 @@ end
|
|
|
176
254
|
|
|
177
255
|
describe "Column references" do
|
|
178
256
|
before do
|
|
179
|
-
@
|
|
180
|
-
|
|
257
|
+
@ds = Sequel::Database.new.dataset
|
|
258
|
+
def @ds.quoted_identifier_append(sql, c)
|
|
259
|
+
sql << "`#{c}`"
|
|
181
260
|
end
|
|
182
|
-
@ds = @c.new(MockDatabase.new)
|
|
183
261
|
@ds.quote_identifiers = true
|
|
184
262
|
end
|
|
185
263
|
|
|
@@ -285,57 +363,22 @@ describe "Symbol" do
|
|
|
285
363
|
@oe.class.should == Sequel::SQL::OrderedExpression
|
|
286
364
|
@oe.descending.should == false
|
|
287
365
|
end
|
|
288
|
-
end
|
|
289
366
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
specify "should convert qualified symbol notation into dot notation" do
|
|
296
|
-
@ds.literal(:abc__def).should == 'abc.def'
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
specify "should convert AS symbol notation into SQL AS notation" do
|
|
300
|
-
@ds.literal(:xyz___x).should == 'xyz AS x'
|
|
301
|
-
@ds.literal(:abc__def___x).should == 'abc.def AS x'
|
|
302
|
-
end
|
|
303
|
-
|
|
304
|
-
specify "should support names with digits" do
|
|
305
|
-
@ds.literal(:abc2).should == 'abc2'
|
|
306
|
-
@ds.literal(:xx__yy3).should == 'xx.yy3'
|
|
307
|
-
@ds.literal(:ab34__temp3_4ax).should == 'ab34.temp3_4ax'
|
|
308
|
-
@ds.literal(:x1___y2).should == 'x1 AS y2'
|
|
309
|
-
@ds.literal(:abc2__def3___ggg4).should == 'abc2.def3 AS ggg4'
|
|
310
|
-
end
|
|
311
|
-
|
|
312
|
-
specify "should support upper case and lower case" do
|
|
313
|
-
@ds.literal(:ABC).should == 'ABC'
|
|
314
|
-
@ds.literal(:Zvashtoy__aBcD).should == 'Zvashtoy.aBcD'
|
|
315
|
-
end
|
|
316
|
-
|
|
317
|
-
specify "should support spaces inside column names" do
|
|
318
|
-
@ds.quote_identifiers = true
|
|
319
|
-
@ds.literal(:"AB C").should == '"AB C"'
|
|
320
|
-
@ds.literal(:"Zvas htoy__aB cD").should == '"Zvas htoy"."aB cD"'
|
|
321
|
-
@ds.literal(:"aB cD___XX XX").should == '"aB cD" AS "XX XX"'
|
|
322
|
-
@ds.literal(:"Zva shtoy__aB cD___XX XX").should == '"Zva shtoy"."aB cD" AS "XX XX"'
|
|
367
|
+
specify "should work correctly with objects" do
|
|
368
|
+
o = Object.new
|
|
369
|
+
def o.sql_literal(ds) "(foo)" end
|
|
370
|
+
@ds.literal(:column.qualify(o)).should == '(foo)."COLUMN"'
|
|
323
371
|
end
|
|
324
372
|
end
|
|
325
373
|
|
|
326
374
|
describe "Symbol" do
|
|
327
375
|
before do
|
|
328
|
-
@ds = Sequel::
|
|
376
|
+
@ds = Sequel::Database.new.dataset
|
|
329
377
|
end
|
|
330
378
|
|
|
331
|
-
specify "should support
|
|
379
|
+
specify "should support sql_function method" do
|
|
332
380
|
:COUNT.sql_function('1').to_s(@ds).should == "COUNT('1')"
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
specify "should inhibit string literalization" do
|
|
336
|
-
db = Sequel::Database.new
|
|
337
|
-
ds = db[:t]
|
|
338
|
-
ds.select(:COUNT.sql_function('1')).sql.should == "SELECT COUNT('1') FROM t"
|
|
381
|
+
@ds.select(:COUNT.sql_function('1')).sql.should == "SELECT COUNT('1')"
|
|
339
382
|
end
|
|
340
383
|
|
|
341
384
|
specify "should support cast method" do
|
|
@@ -346,6 +389,7 @@ describe "Symbol" do
|
|
|
346
389
|
@ds.literal(:abc.sql_subscript(1)).should == "abc[1]"
|
|
347
390
|
@ds.literal(:abc__def.sql_subscript(1)).should == "abc.def[1]"
|
|
348
391
|
@ds.literal(:abc.sql_subscript(1)|2).should == "abc[1, 2]"
|
|
392
|
+
@ds.literal(:abc.sql_subscript(1)[2]).should == "abc[1][2]"
|
|
349
393
|
end
|
|
350
394
|
|
|
351
395
|
specify "should support cast_numeric and cast_string" do
|
|
@@ -367,85 +411,21 @@ describe "Symbol" do
|
|
|
367
411
|
end
|
|
368
412
|
|
|
369
413
|
specify "should allow database independent types when casting" do
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
type
|
|
376
|
-
end
|
|
414
|
+
db = @ds.db
|
|
415
|
+
def db.cast_type_literal(type)
|
|
416
|
+
return :foo if type == Integer
|
|
417
|
+
return :bar if type == String
|
|
418
|
+
type
|
|
377
419
|
end
|
|
378
|
-
@
|
|
379
|
-
:abc.cast(String).to_s(@ds).should == "CAST(abc AS
|
|
380
|
-
:abc.
|
|
381
|
-
:abc.
|
|
382
|
-
:abc.
|
|
383
|
-
:abc.
|
|
384
|
-
:abc.cast_numeric.to_s(@ds2).should == "CAST(abc AS foo)"
|
|
385
|
-
:abc.cast_numeric(String).to_s(@ds2).should == "CAST(abc AS bar)"
|
|
420
|
+
:abc.cast(String).to_s(@ds).should == "CAST(abc AS bar)"
|
|
421
|
+
:abc.cast(String).to_s(@ds).should == "CAST(abc AS bar)"
|
|
422
|
+
:abc.cast_string.to_s(@ds).should == "CAST(abc AS bar)"
|
|
423
|
+
:abc.cast_string(Integer).to_s(@ds).should == "CAST(abc AS foo)"
|
|
424
|
+
:abc.cast_numeric.to_s(@ds).should == "CAST(abc AS foo)"
|
|
425
|
+
:abc.cast_numeric(String).to_s(@ds).should == "CAST(abc AS bar)"
|
|
386
426
|
end
|
|
387
427
|
|
|
388
428
|
specify "should support SQL EXTRACT function via #extract " do
|
|
389
429
|
:abc.extract(:year).to_s(@ds).should == "extract(year FROM abc)"
|
|
390
430
|
end
|
|
391
431
|
end
|
|
392
|
-
|
|
393
|
-
describe "Sequel::SQL::Function#==" do
|
|
394
|
-
specify "should be true for functions with the same name and arguments, false otherwise" do
|
|
395
|
-
a = :date.sql_function(:t)
|
|
396
|
-
b = :date.sql_function(:t)
|
|
397
|
-
a.should == b
|
|
398
|
-
(a == b).should == true
|
|
399
|
-
c = :date.sql_function(:c)
|
|
400
|
-
a.should_not == c
|
|
401
|
-
(a == c).should == false
|
|
402
|
-
d = :time.sql_function(:c)
|
|
403
|
-
a.should_not == d
|
|
404
|
-
c.should_not == d
|
|
405
|
-
(a == d).should == false
|
|
406
|
-
(c == d).should == false
|
|
407
|
-
end
|
|
408
|
-
end
|
|
409
|
-
|
|
410
|
-
describe "Sequel::SQL::OrderedExpression" do
|
|
411
|
-
specify "should #desc" do
|
|
412
|
-
@oe = :column.asc
|
|
413
|
-
@oe.descending.should == false
|
|
414
|
-
@oe.desc.descending.should == true
|
|
415
|
-
end
|
|
416
|
-
|
|
417
|
-
specify "should #asc" do
|
|
418
|
-
@oe = :column.desc
|
|
419
|
-
@oe.descending.should == true
|
|
420
|
-
@oe.asc.descending.should == false
|
|
421
|
-
end
|
|
422
|
-
|
|
423
|
-
specify "should #invert" do
|
|
424
|
-
@oe = :column.desc
|
|
425
|
-
@oe.invert.descending.should == false
|
|
426
|
-
@oe.invert.invert.descending.should == true
|
|
427
|
-
end
|
|
428
|
-
end
|
|
429
|
-
|
|
430
|
-
describe "Expression" do
|
|
431
|
-
specify "should consider objects == only if they have the same attributes" do
|
|
432
|
-
:column.qualify(:table).cast(:type).*(:numeric_column).asc.should == :column.qualify(:table).cast(:type).*(:numeric_column).asc
|
|
433
|
-
:other_column.qualify(:table).cast(:type).*(:numeric_column).asc.should_not == :column.qualify(:table).cast(:type).*(:numeric_column).asc
|
|
434
|
-
|
|
435
|
-
:column.qualify(:table).cast(:type).*(:numeric_column).asc.should eql(:column.qualify(:table).cast(:type).*(:numeric_column).asc)
|
|
436
|
-
:other_column.qualify(:table).cast(:type).*(:numeric_column).asc.should_not eql(:column.qualify(:table).cast(:type).*(:numeric_column).asc)
|
|
437
|
-
end
|
|
438
|
-
|
|
439
|
-
specify "should use the same hash value for objects that have the same attributes" do
|
|
440
|
-
:column.qualify(:table).cast(:type).*(:numeric_column).asc.hash.should == :column.qualify(:table).cast(:type).*(:numeric_column).asc.hash
|
|
441
|
-
:other_column.qualify(:table).cast(:type).*(:numeric_column).asc.hash.should_not == :column.qualify(:table).cast(:type).*(:numeric_column).asc.hash
|
|
442
|
-
|
|
443
|
-
h = {}
|
|
444
|
-
a = :column.qualify(:table).cast(:type).*(:numeric_column).asc
|
|
445
|
-
b = :column.qualify(:table).cast(:type).*(:numeric_column).asc
|
|
446
|
-
h[a] = 1
|
|
447
|
-
h[b] = 2
|
|
448
|
-
h[a].should == 2
|
|
449
|
-
h[b].should == 2
|
|
450
|
-
end
|
|
451
|
-
end
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
|
2
|
+
|
|
3
|
+
describe "Sequel::Plugins::DatasetAssociations" do
|
|
4
|
+
before do
|
|
5
|
+
@db = Sequel::Database.new
|
|
6
|
+
@Base = Class.new(Sequel::Model)
|
|
7
|
+
@Base.plugin :dataset_associations
|
|
8
|
+
|
|
9
|
+
@Artist = Class.new(@Base)
|
|
10
|
+
@Album = Class.new(@Base)
|
|
11
|
+
@Tag = Class.new(@Base)
|
|
12
|
+
|
|
13
|
+
@Artist.meta_def(:name){'Artist'}
|
|
14
|
+
@Album.meta_def(:name){'Album'}
|
|
15
|
+
@Tag.meta_def(:name){'Tag'}
|
|
16
|
+
|
|
17
|
+
@Artist.dataset = @db[:artists]
|
|
18
|
+
@Album.dataset = @db[:albums]
|
|
19
|
+
@Tag.dataset = @db[:tags]
|
|
20
|
+
|
|
21
|
+
@Artist.columns :id, :name
|
|
22
|
+
@Album.columns :id, :name, :artist_id
|
|
23
|
+
@Tag.columns :id, :name
|
|
24
|
+
|
|
25
|
+
@Artist.plugin :many_through_many
|
|
26
|
+
@Artist.one_to_many :albums, :class=>@Album
|
|
27
|
+
@Artist.one_to_one :first_album, :class=>@Album
|
|
28
|
+
@Album.many_to_one :artist, :class=>@Artist
|
|
29
|
+
@Album.many_to_many :tags, :class=>@Tag
|
|
30
|
+
@Tag.many_to_many :albums, :class=>@Album
|
|
31
|
+
@Artist.many_through_many :tags, [[:albums, :artist_id, :id], [:albums_tags, :album_id, :tag_id]], :class=>@Tag
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "should work for many_to_one associations" do
|
|
35
|
+
ds = @Album.artists
|
|
36
|
+
ds.should be_a_kind_of(Sequel::Dataset)
|
|
37
|
+
ds.model.should == @Artist
|
|
38
|
+
ds.sql.should == "SELECT * FROM artists WHERE (artists.id IN (SELECT albums.artist_id FROM albums))"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "should work for one_to_many associations" do
|
|
42
|
+
ds = @Artist.albums
|
|
43
|
+
ds.should be_a_kind_of(Sequel::Dataset)
|
|
44
|
+
ds.model.should == @Album
|
|
45
|
+
ds.sql.should == "SELECT * FROM albums WHERE (albums.artist_id IN (SELECT artists.id FROM artists))"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "should work for one_to_one associations" do
|
|
49
|
+
ds = @Artist.first_albums
|
|
50
|
+
ds.should be_a_kind_of(Sequel::Dataset)
|
|
51
|
+
ds.model.should == @Album
|
|
52
|
+
ds.sql.should == "SELECT * FROM albums WHERE (albums.artist_id IN (SELECT artists.id FROM artists))"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "should work for many_to_many associations" do
|
|
56
|
+
ds = @Album.tags
|
|
57
|
+
ds.should be_a_kind_of(Sequel::Dataset)
|
|
58
|
+
ds.model.should == @Tag
|
|
59
|
+
ds.sql.should == "SELECT tags.* FROM tags WHERE (tags.id IN (SELECT albums_tags.tag_id FROM albums INNER JOIN albums_tags ON (albums_tags.album_id = albums.id)))"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
it "should work for many_through_many associations" do
|
|
63
|
+
ds = @Artist.tags
|
|
64
|
+
ds.should be_a_kind_of(Sequel::Dataset)
|
|
65
|
+
ds.model.should == @Tag
|
|
66
|
+
ds.sql.should == "SELECT tags.* FROM tags WHERE (tags.id IN (SELECT albums_tags.tag_id FROM artists INNER JOIN albums ON (albums.artist_id = artists.id) INNER JOIN albums_tags ON (albums_tags.album_id = albums.id)))"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it "should have an associated method that takes an association symbol" do
|
|
70
|
+
ds = @Album.associated(:artist)
|
|
71
|
+
ds.should be_a_kind_of(Sequel::Dataset)
|
|
72
|
+
ds.model.should == @Artist
|
|
73
|
+
ds.sql.should == "SELECT * FROM artists WHERE (artists.id IN (SELECT albums.artist_id FROM albums))"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it "should raise an Error if an invalid association is given to associated" do
|
|
77
|
+
proc{@Album.associated(:foo)}.should raise_error(Sequel::Error)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "should raise an Error if an unrecognized association type is used" do
|
|
81
|
+
@Album.association_reflection(:artist)[:type] = :foo
|
|
82
|
+
proc{@Album.artists}.should raise_error(Sequel::Error)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "should work correctly when chaining" do
|
|
86
|
+
ds = @Artist.albums.tags
|
|
87
|
+
ds.should be_a_kind_of(Sequel::Dataset)
|
|
88
|
+
ds.model.should == @Tag
|
|
89
|
+
ds.sql.should == "SELECT tags.* FROM tags WHERE (tags.id IN (SELECT albums_tags.tag_id FROM albums INNER JOIN albums_tags ON (albums_tags.album_id = albums.id) WHERE (albums.artist_id IN (SELECT artists.id FROM artists))))"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "should deal correctly with filters before the association method" do
|
|
93
|
+
@Artist.filter(:id=>1).albums.sql.should == "SELECT * FROM albums WHERE (albums.artist_id IN (SELECT artists.id FROM artists WHERE (id = 1)))"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it "should deal correctly with filters after the association method" do
|
|
97
|
+
@Artist.albums.filter(:id=>1).sql.should == "SELECT * FROM albums WHERE ((albums.artist_id IN (SELECT artists.id FROM artists)) AND (id = 1))"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it "should deal correctly with block on the association" do
|
|
101
|
+
@Artist.one_to_many :albums, :clone=>:albums do |ds| ds.filter(:id=>1..100) end
|
|
102
|
+
@Artist.albums.sql.should == "SELECT * FROM albums WHERE ((albums.artist_id IN (SELECT artists.id FROM artists)) AND (id >= 1) AND (id <= 100))"
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
it "should deal correctly with :conditions option on the association" do
|
|
106
|
+
@Artist.one_to_many :albums, :clone=>:albums, :conditions=>{:id=>1..100}
|
|
107
|
+
@Artist.albums.sql.should == "SELECT * FROM albums WHERE ((albums.artist_id IN (SELECT artists.id FROM artists)) AND (id >= 1) AND (id <= 100))"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it "should deal correctly with :distinct option on the association" do
|
|
111
|
+
@Artist.one_to_many :albums, :clone=>:albums, :distinct=>true
|
|
112
|
+
@Artist.albums.sql.should == "SELECT DISTINCT * FROM albums WHERE (albums.artist_id IN (SELECT artists.id FROM artists))"
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it "should deal correctly with :eager option on the association" do
|
|
116
|
+
@Artist.one_to_many :albums, :clone=>:albums, :eager=>:tags
|
|
117
|
+
@Artist.albums.opts[:eager].should == {:tags=>nil}
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
it "should deal correctly with :eager_block option on the association, ignoring the association block" do
|
|
121
|
+
@Artist.one_to_many :albums, :clone=>:albums, :eager_block=>proc{|ds| ds.filter(:id=>1..100)} do |ds| ds.filter(:id=>2..200) end
|
|
122
|
+
@Artist.albums.sql.should == "SELECT * FROM albums WHERE ((albums.artist_id IN (SELECT artists.id FROM artists)) AND (id >= 1) AND (id <= 100))"
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it "should deal correctly with :extend option on the association" do
|
|
126
|
+
@Artist.one_to_many :albums, :clone=>:albums, :extend=>Module.new{def foo(x) filter(:id=>x) end}
|
|
127
|
+
@Artist.albums.foo(1).sql.should == "SELECT * FROM albums WHERE ((albums.artist_id IN (SELECT artists.id FROM artists)) AND (id = 1))"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
it "should deal correctly with :order option on the association" do
|
|
131
|
+
@Artist.one_to_many :albums, :clone=>:albums, :order=>:name
|
|
132
|
+
@Artist.albums.sql.should == "SELECT * FROM albums WHERE (albums.artist_id IN (SELECT artists.id FROM artists)) ORDER BY name"
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
it "should deal correctly with :select option on the association" do
|
|
136
|
+
@Artist.one_to_many :albums, :clone=>:albums, :select=>[:id, :name]
|
|
137
|
+
@Artist.albums.sql.should == "SELECT id, name FROM albums WHERE (albums.artist_id IN (SELECT artists.id FROM artists))"
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
describe "Sequel::Plugins::DatasetAssociations with composite keys" do
|
|
142
|
+
before do
|
|
143
|
+
@db = Sequel::Database.new
|
|
144
|
+
@Base = Class.new(Sequel::Model)
|
|
145
|
+
@Base.plugin :dataset_associations
|
|
146
|
+
|
|
147
|
+
@Artist = Class.new(@Base)
|
|
148
|
+
@Album = Class.new(@Base)
|
|
149
|
+
@Tag = Class.new(@Base)
|
|
150
|
+
|
|
151
|
+
@Artist.meta_def(:name){'Artist'}
|
|
152
|
+
@Album.meta_def(:name){'Album'}
|
|
153
|
+
@Tag.meta_def(:name){'Tag'}
|
|
154
|
+
|
|
155
|
+
@Artist.dataset = @db[:artists]
|
|
156
|
+
@Album.dataset = @db[:albums]
|
|
157
|
+
@Tag.dataset = @db[:tags]
|
|
158
|
+
|
|
159
|
+
@Artist.set_primary_key([:id1, :id2])
|
|
160
|
+
@Album.set_primary_key([:id1, :id2])
|
|
161
|
+
@Tag.set_primary_key([:id1, :id2])
|
|
162
|
+
|
|
163
|
+
@Artist.columns :id1, :id2, :name
|
|
164
|
+
@Album.columns :id1, :id2, :name, :artist_id1, :artist_id2
|
|
165
|
+
@Tag.columns :id1, :id2, :name
|
|
166
|
+
|
|
167
|
+
@Artist.plugin :many_through_many
|
|
168
|
+
@Artist.one_to_many :albums, :class=>@Album, :key=>[:artist_id1, :artist_id2]
|
|
169
|
+
@Artist.one_to_one :first_album, :class=>@Album, :key=>[:artist_id1, :artist_id2]
|
|
170
|
+
@Album.many_to_one :artist, :class=>@Artist, :key=>[:artist_id1, :artist_id2]
|
|
171
|
+
@Album.many_to_many :tags, :class=>@Tag, :left_key=>[:album_id1, :album_id2], :right_key=>[:tag_id1, :tag_id2]
|
|
172
|
+
@Tag.many_to_many :albums, :class=>@Album, :right_key=>[:album_id1, :album_id2], :left_key=>[:tag_id1, :tag_id2]
|
|
173
|
+
@Artist.many_through_many :tags, [[:albums, [:artist_id1, :artist_id2], [:id1, :id2]], [:albums_tags, [:album_id1, :album_id2], [:tag_id1, :tag_id2]]], :class=>@Tag
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
it "should work for many_to_one associations" do
|
|
177
|
+
@Album.artists.sql.should == "SELECT * FROM artists WHERE ((artists.id1, artists.id2) IN (SELECT albums.artist_id1, albums.artist_id2 FROM albums))"
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
it "should work for one_to_many associations" do
|
|
181
|
+
@Artist.albums.sql.should == "SELECT * FROM albums WHERE ((albums.artist_id1, albums.artist_id2) IN (SELECT artists.id1, artists.id2 FROM artists))"
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
it "should work for one_to_one associations" do
|
|
185
|
+
@Artist.first_albums.sql.should == "SELECT * FROM albums WHERE ((albums.artist_id1, albums.artist_id2) IN (SELECT artists.id1, artists.id2 FROM artists))"
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
it "should work for many_to_many associations" do
|
|
189
|
+
@Album.tags.sql.should == "SELECT tags.* FROM tags WHERE ((tags.id1, tags.id2) IN (SELECT albums_tags.tag_id1, albums_tags.tag_id2 FROM albums INNER JOIN albums_tags ON ((albums_tags.album_id1 = albums.id1) AND (albums_tags.album_id2 = albums.id2))))"
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
it "should work for many_through_many associations" do
|
|
193
|
+
@Artist.tags.sql.should == "SELECT tags.* FROM tags WHERE ((tags.id1, tags.id2) IN (SELECT albums_tags.tag_id1, albums_tags.tag_id2 FROM artists INNER JOIN albums ON ((albums.artist_id1 = artists.id1) AND (albums.artist_id2 = artists.id2)) INNER JOIN albums_tags ON ((albums_tags.album_id1 = albums.id1) AND (albums_tags.album_id2 = albums.id2))))"
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
it "should work correctly when chaining" do
|
|
197
|
+
@Artist.albums.tags.sql.should == "SELECT tags.* FROM tags WHERE ((tags.id1, tags.id2) IN (SELECT albums_tags.tag_id1, albums_tags.tag_id2 FROM albums INNER JOIN albums_tags ON ((albums_tags.album_id1 = albums.id1) AND (albums_tags.album_id2 = albums.id2)) WHERE ((albums.artist_id1, albums.artist_id2) IN (SELECT artists.id1, artists.id2 FROM artists))))"
|
|
198
|
+
end
|
|
199
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
|
2
|
+
|
|
3
|
+
describe "Sequel::Plugins::DefaultsSetter" do
|
|
4
|
+
before do
|
|
5
|
+
@db = db = Sequel::Database.new
|
|
6
|
+
@c = c = Class.new(Sequel::Model(db[:foo]))
|
|
7
|
+
@c.instance_variable_set(:@db_schema, {:a=>{}})
|
|
8
|
+
@c.plugin :defaults_setter
|
|
9
|
+
@c.columns :a
|
|
10
|
+
@pr = proc{|x| db.meta_def(:schema){|*| [[:a, {:ruby_default => x}]]}; c.dataset = c.dataset; c}
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "should set default value upon initialization" do
|
|
14
|
+
@pr.call(2).new.values.should == {:a=>2}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should not mark the column as modified" do
|
|
18
|
+
@pr.call(2).new.changed_columns.should == []
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "should not set a default of nil" do
|
|
22
|
+
@pr.call(nil).new.values.should == {}
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "should not override a given value" do
|
|
26
|
+
@pr.call(2)
|
|
27
|
+
@c.new('a'=>3).values.should == {:a=>3}
|
|
28
|
+
@c.new('a'=>nil).values.should == {:a=>nil}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "should work correctly when subclassing" do
|
|
32
|
+
Class.new(@pr.call(2)).new.values.should == {:a=>2}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "should contain the default values in default_values" do
|
|
36
|
+
@pr.call(2).default_values.should == {:a=>2}
|
|
37
|
+
@pr.call(nil).default_values.should == {}
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "should allow modifications of default values" do
|
|
41
|
+
@pr.call(2)
|
|
42
|
+
@c.default_values[:a] = 3
|
|
43
|
+
@c.new.values.should == {:a => 3}
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "should allow proc default values" do
|
|
47
|
+
@pr.call(2)
|
|
48
|
+
@c.default_values[:a] = proc{3}
|
|
49
|
+
@c.new.values.should == {:a => 3}
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "should have procs that set default values set them to nil" do
|
|
53
|
+
@pr.call(2)
|
|
54
|
+
@c.default_values[:a] = proc{nil}
|
|
55
|
+
@c.new.values.should == {:a => nil}
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "should work correctly on a model without a dataset" do
|
|
59
|
+
@pr.call(2)
|
|
60
|
+
c = Class.new(Sequel::Model(@db[:bar]))
|
|
61
|
+
c.plugin :defaults_setter
|
|
62
|
+
c.default_values.should == {:a=>2}
|
|
63
|
+
end
|
|
64
|
+
end
|