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
|
@@ -6,10 +6,31 @@
|
|
|
6
6
|
|
|
7
7
|
module Sequel
|
|
8
8
|
class Database
|
|
9
|
+
# Dump foreign key constraints for all tables as a migration. This complements
|
|
10
|
+
# the :foreign_keys=>false option to dump_schema_migration. This only dumps
|
|
11
|
+
# the constraints (not the columns) using alter_table/add_foreign_key with an
|
|
12
|
+
# array of columns.
|
|
13
|
+
#
|
|
14
|
+
# Note that the migration this produces does not have a down
|
|
15
|
+
# block, so you cannot reverse it.
|
|
16
|
+
def dump_foreign_key_migration(options={})
|
|
17
|
+
ts = tables(options)
|
|
18
|
+
<<END_MIG
|
|
19
|
+
Sequel.migration do
|
|
20
|
+
up do
|
|
21
|
+
#{ts.sort_by{|t| t.to_s}.map{|t| dump_table_foreign_keys(t)}.reject{|x| x == ''}.join("\n\n").gsub(/^/o, ' ')}
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
END_MIG
|
|
25
|
+
end
|
|
26
|
+
|
|
9
27
|
# Dump indexes for all tables as a migration. This complements
|
|
10
28
|
# the :indexes=>false option to dump_schema_migration. Options:
|
|
11
29
|
# * :same_db - Create a dump for the same database type, so
|
|
12
30
|
# don't ignore errors if the index statements fail.
|
|
31
|
+
# * :index_names - If set to false, don't record names of indexes. If
|
|
32
|
+
# set to :namespace, prepend the table name to the index name if the
|
|
33
|
+
# database does not use a global index namespace.
|
|
13
34
|
def dump_indexes_migration(options={})
|
|
14
35
|
ts = tables(options)
|
|
15
36
|
<<END_MIG
|
|
@@ -19,7 +40,7 @@ Sequel.migration do
|
|
|
19
40
|
end
|
|
20
41
|
|
|
21
42
|
down do
|
|
22
|
-
#{ts.sort_by{|t| t.to_s}.map{|t| dump_table_indexes(t, :drop_index, options)}.reject{|x| x == ''}.join("\n\n").gsub(/^/o, ' ')}
|
|
43
|
+
#{ts.sort_by{|t| t.to_s}.reverse.map{|t| dump_table_indexes(t, :drop_index, options)}.reject{|x| x == ''}.join("\n\n").gsub(/^/o, ' ')}
|
|
23
44
|
end
|
|
24
45
|
end
|
|
25
46
|
END_MIG
|
|
@@ -32,18 +53,37 @@ END_MIG
|
|
|
32
53
|
# ruby types, but there is no guarantee that the migration generated
|
|
33
54
|
# will yield the same type. Without this set, types that aren't
|
|
34
55
|
# recognized will be translated to a string-like type.
|
|
56
|
+
# * :foreign_keys - If set to false, don't dump foreign_keys
|
|
35
57
|
# * :indexes - If set to false, don't dump indexes (they can be added
|
|
36
58
|
# later via dump_index_migration).
|
|
59
|
+
# * :index_names - If set to false, don't record names of indexes. If
|
|
60
|
+
# set to :namespace, prepend the table name to the index name.
|
|
37
61
|
def dump_schema_migration(options={})
|
|
38
|
-
|
|
62
|
+
options = options.dup
|
|
63
|
+
if options[:indexes] == false && !options.has_key?(:foreign_keys)
|
|
64
|
+
# Unless foreign_keys option is specifically set, disable if indexes
|
|
65
|
+
# are disabled, as foreign keys that point to non-primary keys rely
|
|
66
|
+
# on unique indexes being created first
|
|
67
|
+
options[:foreign_keys] = false
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
ts = sort_dumped_tables(tables(options), options)
|
|
71
|
+
skipped_fks = if sfk = options[:skipped_foreign_keys]
|
|
72
|
+
# Handle skipped foreign keys by adding them at the end via
|
|
73
|
+
# alter_table/add_foreign_key. Note that skipped foreign keys
|
|
74
|
+
# probably result in a broken down migration.
|
|
75
|
+
sfka = sfk.sort_by{|table, fks| table.to_s}.map{|table, fks| dump_add_fk_constraints(table, fks.values)}
|
|
76
|
+
sfka.join("\n\n").gsub(/^/o, ' ') unless sfka.empty?
|
|
77
|
+
end
|
|
78
|
+
|
|
39
79
|
<<END_MIG
|
|
40
80
|
Sequel.migration do
|
|
41
81
|
up do
|
|
42
|
-
#{ts.
|
|
82
|
+
#{ts.map{|t| dump_table_schema(t, options)}.join("\n\n").gsub(/^/o, ' ')}#{"\n \n" if skipped_fks}#{skipped_fks}
|
|
43
83
|
end
|
|
44
84
|
|
|
45
85
|
down do
|
|
46
|
-
drop_table(#{ts.
|
|
86
|
+
drop_table(#{ts.reverse.inspect[1...-1]})
|
|
47
87
|
end
|
|
48
88
|
end
|
|
49
89
|
END_MIG
|
|
@@ -53,24 +93,9 @@ END_MIG
|
|
|
53
93
|
# table's schema. Takes the same options as dump_schema_migration.
|
|
54
94
|
def dump_table_schema(table, options={})
|
|
55
95
|
table = table.value.to_s if table.is_a?(SQL::Identifier)
|
|
56
|
-
|
|
57
|
-
s = schema(table).dup
|
|
58
|
-
pks = s.find_all{|x| x.last[:primary_key] == true}.map{|x| x.first}
|
|
59
|
-
options = options.merge(:single_pk=>true) if pks.length == 1
|
|
60
|
-
m = method(:column_schema_to_generator_opts)
|
|
61
|
-
im = method(:index_to_generator_opts)
|
|
62
|
-
begin
|
|
63
|
-
indexes = indexes(table).sort_by{|k,v| k.to_s} if options[:indexes] != false
|
|
64
|
-
rescue Sequel::NotImplemented
|
|
65
|
-
nil
|
|
66
|
-
end
|
|
67
|
-
gen = Schema::Generator.new(self) do
|
|
68
|
-
s.each{|name, info| send(*m.call(name, info, options))}
|
|
69
|
-
primary_key(pks) if !@primary_key && pks.length > 0
|
|
70
|
-
indexes.each{|iname, iopts| send(:index, iopts[:columns], im.call(table, iname, iopts))} if indexes
|
|
71
|
-
end
|
|
96
|
+
gen = dump_table_generator(table, options)
|
|
72
97
|
commands = [gen.dump_columns, gen.dump_constraints, gen.dump_indexes].reject{|x| x == ''}.join("\n\n")
|
|
73
|
-
"create_table(#{table.inspect}#{', :ignore_index_errors=>true' if !options[:same_db] && options[:indexes] != false &&
|
|
98
|
+
"create_table(#{table.inspect}#{', :ignore_index_errors=>true' if !options[:same_db] && options[:indexes] != false && !gen.indexes.empty?}) do\n#{commands.gsub(/^/o, ' ')}\nend"
|
|
74
99
|
end
|
|
75
100
|
|
|
76
101
|
private
|
|
@@ -82,7 +107,7 @@ END_MIG
|
|
|
82
107
|
if default.is_a?(String) && options[:same_db] && use_column_schema_to_ruby_default_fallback?
|
|
83
108
|
default = default.to_s
|
|
84
109
|
def default.inspect
|
|
85
|
-
"#{super}.lit"
|
|
110
|
+
"#{super}.lit" # core_sql use
|
|
86
111
|
end
|
|
87
112
|
default
|
|
88
113
|
end
|
|
@@ -93,6 +118,7 @@ END_MIG
|
|
|
93
118
|
def column_schema_to_generator_opts(name, schema, options)
|
|
94
119
|
if options[:single_pk] && schema_autoincrementing_primary_key?(schema)
|
|
95
120
|
type_hash = options[:same_db] ? {:type=>schema[:db_type]} : column_schema_to_ruby_type(schema)
|
|
121
|
+
[:table, :key, :on_delete, :on_update, :deferrable].each{|f| type_hash[f] = schema[f] if schema[f]}
|
|
96
122
|
if type_hash == {:type=>Integer} || type_hash == {:type=>"integer"}
|
|
97
123
|
[:primary_key, name]
|
|
98
124
|
else
|
|
@@ -109,7 +135,12 @@ END_MIG
|
|
|
109
135
|
end
|
|
110
136
|
col_opts.delete(:default) if col_opts[:default].nil?
|
|
111
137
|
col_opts[:null] = false if schema[:allow_null] == false
|
|
112
|
-
|
|
138
|
+
if table = schema[:table]
|
|
139
|
+
[:key, :on_delete, :on_update, :deferrable].each{|f| col_opts[f] = schema[f] if schema[f]}
|
|
140
|
+
[:foreign_key, name, table, col_opts]
|
|
141
|
+
else
|
|
142
|
+
[:column, name, type, col_opts]
|
|
143
|
+
end
|
|
113
144
|
end
|
|
114
145
|
end
|
|
115
146
|
|
|
@@ -118,9 +149,15 @@ END_MIG
|
|
|
118
149
|
# database type is not recognized, return it as a String type.
|
|
119
150
|
def column_schema_to_ruby_type(schema)
|
|
120
151
|
case t = schema[:db_type].downcase
|
|
121
|
-
when /\A(
|
|
122
|
-
|
|
123
|
-
|
|
152
|
+
when /\A(medium|small)?int(?:eger)?(?:\((\d+)\))?( unsigned)?\z/o
|
|
153
|
+
if !$1 && $2 && $2.to_i >= 10 && $3
|
|
154
|
+
# Unsigned integer type with 10 digits can potentially contain values which
|
|
155
|
+
# don't fit signed integer type, so use bigint type in target database.
|
|
156
|
+
{:type=>Bignum}
|
|
157
|
+
else
|
|
158
|
+
{:type=>Integer}
|
|
159
|
+
end
|
|
160
|
+
when /\Atinyint(?:\((\d+)\))?(?: unsigned)?\z/o
|
|
124
161
|
{:type =>schema[:type] == :boolean ? TrueClass : Integer}
|
|
125
162
|
when /\Abigint(?:\((?:\d+)\))?(?: unsigned)?\z/o
|
|
126
163
|
{:type=>Bignum}
|
|
@@ -149,32 +186,189 @@ END_MIG
|
|
|
149
186
|
{:type=>BigDecimal, :size=>(s.empty? ? nil : s)}
|
|
150
187
|
when /\A(?:bytea|(?:tiny|medium|long)?blob|(?:var)?binary)(?:\((\d+)\))?\z/o
|
|
151
188
|
{:type=>File, :size=>($1.to_i if $1)}
|
|
152
|
-
when
|
|
189
|
+
when /\A(?:year|(?:int )?identity)\z/o
|
|
153
190
|
{:type=>Integer}
|
|
154
191
|
else
|
|
155
192
|
{:type=>String}
|
|
156
193
|
end
|
|
157
194
|
end
|
|
158
195
|
|
|
196
|
+
# For the table and foreign key metadata array, return an alter_table
|
|
197
|
+
# string that would add the foreign keys if run in a migration.
|
|
198
|
+
def dump_add_fk_constraints(table, fks)
|
|
199
|
+
sfks = "alter_table(#{table.inspect}) do\n"
|
|
200
|
+
sfks << Schema::Generator.new(self) do
|
|
201
|
+
fks.sort_by{|fk| fk[:columns].map{|c| c.to_s}}.each do |fk|
|
|
202
|
+
foreign_key fk[:columns], fk
|
|
203
|
+
end
|
|
204
|
+
end.dump_constraints.gsub(/^foreign_key /, ' add_foreign_key ')
|
|
205
|
+
sfks << "\nend"
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# For the table given, get the list of foreign keys and return an alter_table
|
|
209
|
+
# string that would add the foreign keys if run in a migration.
|
|
210
|
+
def dump_table_foreign_keys(table, options={})
|
|
211
|
+
begin
|
|
212
|
+
fks = foreign_key_list(table, options).sort_by{|fk| fk[:columns].map{|c| c.to_s}}
|
|
213
|
+
rescue Sequel::NotImplemented
|
|
214
|
+
return ''
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
if fks.empty?
|
|
218
|
+
''
|
|
219
|
+
else
|
|
220
|
+
dump_add_fk_constraints(table, fks)
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# Return a Schema::Generator object that will recreate the
|
|
225
|
+
# table's schema. Takes the same options as dump_schema_migration.
|
|
226
|
+
def dump_table_generator(table, options={})
|
|
227
|
+
table = table.value.to_s if table.is_a?(SQL::Identifier)
|
|
228
|
+
raise(Error, "must provide table as a Symbol, String, or Sequel::SQL::Identifier") unless [String, Symbol].any?{|c| table.is_a?(c)}
|
|
229
|
+
s = schema(table).dup
|
|
230
|
+
pks = s.find_all{|x| x.last[:primary_key] == true}.map{|x| x.first}
|
|
231
|
+
options = options.merge(:single_pk=>true) if pks.length == 1
|
|
232
|
+
m = method(:column_schema_to_generator_opts)
|
|
233
|
+
im = method(:index_to_generator_opts)
|
|
234
|
+
|
|
235
|
+
if options[:indexes] != false
|
|
236
|
+
begin
|
|
237
|
+
indexes = indexes(table).sort_by{|k,v| k.to_s}
|
|
238
|
+
rescue Sequel::NotImplemented
|
|
239
|
+
nil
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
if options[:foreign_keys] != false
|
|
244
|
+
begin
|
|
245
|
+
fk_list = foreign_key_list(table)
|
|
246
|
+
|
|
247
|
+
if (sfk = options[:skipped_foreign_keys]) && (sfkt = sfk[table])
|
|
248
|
+
fk_list.delete_if{|fk| sfkt.has_key?(fk[:columns])}
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
composite_fks, single_fks = fk_list.partition{|h| h[:columns].length > 1}
|
|
252
|
+
fk_hash = {}
|
|
253
|
+
|
|
254
|
+
single_fks.each do |fk|
|
|
255
|
+
column = fk.delete(:columns).first
|
|
256
|
+
fk.delete(:name)
|
|
257
|
+
fk_hash[column] = fk
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
s = s.map do |name, info|
|
|
261
|
+
if fk_info = fk_hash[name]
|
|
262
|
+
[name, fk_info.merge(info)]
|
|
263
|
+
else
|
|
264
|
+
[name, info]
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
rescue Sequel::NotImplemented
|
|
268
|
+
nil
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
Schema::Generator.new(self) do
|
|
273
|
+
s.each{|name, info| send(*m.call(name, info, options))}
|
|
274
|
+
primary_key(pks) if !@primary_key && pks.length > 0
|
|
275
|
+
indexes.each{|iname, iopts| send(:index, iopts[:columns], im.call(table, iname, iopts, options))} if indexes
|
|
276
|
+
composite_fks.each{|fk| send(:foreign_key, fk[:columns], fk)} if composite_fks
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
|
|
159
280
|
# Return a string that containing add_index/drop_index method calls for
|
|
160
281
|
# creating the index migration.
|
|
161
282
|
def dump_table_indexes(table, meth, options={})
|
|
162
|
-
|
|
283
|
+
begin
|
|
284
|
+
indexes = indexes(table).sort_by{|k,v| k.to_s}
|
|
285
|
+
rescue Sequel::NotImplemented
|
|
286
|
+
return ''
|
|
287
|
+
end
|
|
163
288
|
im = method(:index_to_generator_opts)
|
|
164
|
-
indexes = indexes(table).sort_by{|k,v| k.to_s}
|
|
165
289
|
gen = Schema::Generator.new(self) do
|
|
166
|
-
indexes.each{|iname, iopts| send(:index, iopts[:columns], im.call(table, iname, iopts))}
|
|
290
|
+
indexes.each{|iname, iopts| send(:index, iopts[:columns], im.call(table, iname, iopts, options))}
|
|
167
291
|
end
|
|
168
292
|
gen.dump_indexes(meth=>table, :ignore_errors=>!options[:same_db])
|
|
169
293
|
end
|
|
170
294
|
|
|
171
295
|
# Convert the parsed index information into options to the Generators index method.
|
|
172
|
-
def index_to_generator_opts(table, name, index_opts)
|
|
296
|
+
def index_to_generator_opts(table, name, index_opts, options={})
|
|
173
297
|
h = {}
|
|
174
|
-
|
|
298
|
+
if options[:index_names] != false && default_index_name(table, index_opts[:columns]) != name.to_s
|
|
299
|
+
if options[:index_names] == :namespace && !global_index_namespace?
|
|
300
|
+
h[:name] = "#{table}_#{name}".to_sym
|
|
301
|
+
else
|
|
302
|
+
h[:name] = name
|
|
303
|
+
end
|
|
304
|
+
end
|
|
175
305
|
h[:unique] = true if index_opts[:unique]
|
|
176
306
|
h
|
|
177
307
|
end
|
|
308
|
+
|
|
309
|
+
# Sort the tables so that referenced tables are created before tables that
|
|
310
|
+
# reference them, and then by name. If foreign keys are disabled, just sort by name.
|
|
311
|
+
def sort_dumped_tables(tables, options={})
|
|
312
|
+
sort_topologically = if options[:foreign_keys] != false
|
|
313
|
+
begin
|
|
314
|
+
foreign_key_list(:some_table_that_does_not_exist)
|
|
315
|
+
true
|
|
316
|
+
rescue Sequel::NotImplemented
|
|
317
|
+
false
|
|
318
|
+
rescue
|
|
319
|
+
true
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
if sort_topologically
|
|
324
|
+
table_fks = {}
|
|
325
|
+
tables.each{|t| table_fks[t] = foreign_key_list(t)}
|
|
326
|
+
# Remove self referential foreign keys, not important when sorting.
|
|
327
|
+
table_fks.each{|t, fks| fks.delete_if{|fk| fk[:table] == t}}
|
|
328
|
+
tables, skipped_foreign_keys = sort_dumped_tables_topologically(table_fks, [])
|
|
329
|
+
options[:skipped_foreign_keys] = skipped_foreign_keys
|
|
330
|
+
tables
|
|
331
|
+
else
|
|
332
|
+
tables.sort_by{|t| t.to_s}
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
# Do a topological sort of tables, so that referenced tables
|
|
337
|
+
# come before referencing tables. Returns an array of sorted
|
|
338
|
+
# tables and a hash of skipped foreign keys. The hash will be
|
|
339
|
+
# empty unless there are circular dependencies.
|
|
340
|
+
def sort_dumped_tables_topologically(table_fks, sorted_tables)
|
|
341
|
+
skipped_foreign_keys = {}
|
|
342
|
+
|
|
343
|
+
until table_fks.empty?
|
|
344
|
+
this_loop = []
|
|
345
|
+
|
|
346
|
+
table_fks.each do |table, fks|
|
|
347
|
+
fks.delete_if{|fk| !table_fks.has_key?(fk[:table])}
|
|
348
|
+
this_loop << table if fks.empty?
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
if this_loop.empty?
|
|
352
|
+
# No tables were changed this round, there must be a circular dependency.
|
|
353
|
+
# Break circular dependency by picking the table with the least number of
|
|
354
|
+
# outstanding foreign keys and skipping those foreign keys.
|
|
355
|
+
# The skipped foreign keys will be added at the end of the
|
|
356
|
+
# migration.
|
|
357
|
+
skip_table, skip_fks = table_fks.sort_by{|table, fks| [fks.length, table.to_s]}.first
|
|
358
|
+
skip_fks_hash = skipped_foreign_keys[skip_table] = {}
|
|
359
|
+
skip_fks.each{|fk| skip_fks_hash[fk[:columns]] = fk}
|
|
360
|
+
this_loop << skip_table
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
# Add sorted tables from this loop to the final list
|
|
364
|
+
sorted_tables.concat(this_loop.sort_by{|t| t.to_s})
|
|
365
|
+
|
|
366
|
+
# Remove tables that were handled this loop
|
|
367
|
+
this_loop.each{|t| table_fks.delete(t)}
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
[sorted_tables, skipped_foreign_keys]
|
|
371
|
+
end
|
|
178
372
|
|
|
179
373
|
# Don't use the "...".lit fallback on MySQL, since the defaults it uses aren't
|
|
180
374
|
# valid literal SQL values.
|
|
@@ -190,6 +384,10 @@ END_MIG
|
|
|
190
384
|
def dump_columns
|
|
191
385
|
strings = []
|
|
192
386
|
cols = columns.dup
|
|
387
|
+
cols.each do |x|
|
|
388
|
+
x.delete(:on_delete) if x[:on_delete] == :no_action
|
|
389
|
+
x.delete(:on_update) if x[:on_update] == :no_action
|
|
390
|
+
end
|
|
193
391
|
if pkn = primary_key_name
|
|
194
392
|
cols.delete_if{|x| x[:name] == pkn}
|
|
195
393
|
pk = @primary_key.dup
|
|
@@ -200,12 +398,17 @@ END_MIG
|
|
|
200
398
|
cols.each do |c|
|
|
201
399
|
c = c.dup
|
|
202
400
|
name = c.delete(:name)
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
"#{type.name} #{name.inspect}#{opts}"
|
|
401
|
+
strings << if table = c.delete(:table)
|
|
402
|
+
c.delete(:type) if c[:type] == Integer || c[:type] == 'integer'
|
|
403
|
+
"foreign_key #{name.inspect}, #{table.inspect}#{opts_inspect(c)}"
|
|
207
404
|
else
|
|
208
|
-
|
|
405
|
+
type = c.delete(:type)
|
|
406
|
+
opts = opts_inspect(c)
|
|
407
|
+
if type.is_a?(Class)
|
|
408
|
+
"#{type.name} #{name.inspect}#{opts}"
|
|
409
|
+
else
|
|
410
|
+
"column #{name.inspect}, #{type.inspect}#{opts}"
|
|
411
|
+
end
|
|
209
412
|
end
|
|
210
413
|
end
|
|
211
414
|
strings.join("\n")
|
|
@@ -226,6 +429,13 @@ END_MIG
|
|
|
226
429
|
else
|
|
227
430
|
"#{name ? "constraint #{name.inspect}," : 'check'} #{c[:check].map{|x| x.inspect}.join(', ')}"
|
|
228
431
|
end
|
|
432
|
+
when :foreign_key
|
|
433
|
+
c.delete(:on_delete) if c[:on_delete] == :no_action
|
|
434
|
+
c.delete(:on_update) if c[:on_update] == :no_action
|
|
435
|
+
c.delete(:deferrable) unless c[:deferrable]
|
|
436
|
+
cols = c.delete(:columns)
|
|
437
|
+
table = c.delete(:table)
|
|
438
|
+
"#{type} #{cols.inspect}, #{table.inspect}#{opts_inspect(c)}"
|
|
229
439
|
else
|
|
230
440
|
cols = c.delete(:columns)
|
|
231
441
|
"#{type} #{cols.inspect}#{opts_inspect(c)}"
|
|
@@ -251,11 +461,15 @@ END_MIG
|
|
|
251
461
|
"index #{cols.inspect}#{opts_inspect(c)}"
|
|
252
462
|
end
|
|
253
463
|
end
|
|
464
|
+
is = is.reverse if options[:drop_index]
|
|
254
465
|
is.join("\n")
|
|
255
466
|
end
|
|
256
467
|
|
|
257
468
|
private
|
|
258
469
|
|
|
470
|
+
# Return a string that converts the given options into one
|
|
471
|
+
# suitable for literal ruby code, handling default values
|
|
472
|
+
# that don't default to a literal interpretation.
|
|
259
473
|
def opts_inspect(opts)
|
|
260
474
|
if opts[:default]
|
|
261
475
|
opts = opts.dup
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# The select_remove extension adds Sequel::Dataset#select_remove for removing existing selected
|
|
2
|
+
# columns from a dataset. It's not part of Sequel core as it is rarely needed and has
|
|
3
|
+
# some corner cases where it can't work correctly.
|
|
4
|
+
|
|
5
|
+
module Sequel
|
|
6
|
+
class Dataset
|
|
7
|
+
# Remove columns from the list of selected columns. If any of the currently selected
|
|
8
|
+
# columns use expressions/aliases, this will remove selected columns with the given
|
|
9
|
+
# aliases. It will also remove entries from the selection that match exactly:
|
|
10
|
+
#
|
|
11
|
+
# # Assume columns a, b, and c in items table
|
|
12
|
+
# DB[:items] # SELECT * FROM items
|
|
13
|
+
# DB[:items].select_remove(:c) # SELECT a, b FROM items
|
|
14
|
+
# DB[:items].select(:a, :b___c, :c___b).select_remove(:c) # SELECT a, c AS b FROM items
|
|
15
|
+
# DB[:items].select(:a, :b___c, :c___b).select_remove(:c___b) # SELECT a, b AS c FROM items
|
|
16
|
+
#
|
|
17
|
+
# Note that there are a few cases where this method may not work correctly:
|
|
18
|
+
#
|
|
19
|
+
# * This dataset joins multiple tables and does not have an existing explicit selection.
|
|
20
|
+
# In this case, the code will currently use unqualified column names for all columns
|
|
21
|
+
# the dataset returns, except for the columns given.
|
|
22
|
+
# * This dataset has an existing explicit selection containing an item that returns
|
|
23
|
+
# multiple database columns (e.g. :table.*, 'column1, column2'.lit). In this case,
|
|
24
|
+
# the behavior is undefined and this method should not be used.
|
|
25
|
+
#
|
|
26
|
+
# There may be other cases where this method does not work correctly, use it with caution.
|
|
27
|
+
def select_remove(*cols)
|
|
28
|
+
if (sel = @opts[:select]) && !sel.empty?
|
|
29
|
+
select(*(columns.zip(sel).reject{|c, s| cols.include?(c)}.map{|c, s| s} - cols))
|
|
30
|
+
else
|
|
31
|
+
select(*(columns - cols))
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# The server_block extension adds the Database#with_server method, which takes a shard
|
|
2
|
+
# argument and a block, and makes it so that access inside the block will use the
|
|
3
|
+
# specified shard by default.
|
|
4
|
+
#
|
|
5
|
+
# First, you need to enable it on the database object:
|
|
6
|
+
#
|
|
7
|
+
# Sequel.extension :server_block
|
|
8
|
+
# DB.extend Sequel::ServerBlock
|
|
9
|
+
#
|
|
10
|
+
# Then you can call with_server:
|
|
11
|
+
#
|
|
12
|
+
# DB.with_server(:shard1) do
|
|
13
|
+
# DB[:a].all # Uses shard1
|
|
14
|
+
# DB[:a].server(:shard2).all # Uses shard2
|
|
15
|
+
# end
|
|
16
|
+
# DB[:a].all # Uses default
|
|
17
|
+
#
|
|
18
|
+
# You can even nest calls to with_server:
|
|
19
|
+
#
|
|
20
|
+
# DB.with_server(:shard1) do
|
|
21
|
+
# DB[:a].all # Uses shard1
|
|
22
|
+
# DB.with_server(:shard2) do
|
|
23
|
+
# DB[:a].all # Uses shard2
|
|
24
|
+
# end
|
|
25
|
+
# DB[:a].all # Uses shard1
|
|
26
|
+
# end
|
|
27
|
+
# DB[:a].all # Uses default
|
|
28
|
+
#
|
|
29
|
+
# Note this this extension assumes the following shard names should use the
|
|
30
|
+
# server/shard passed to with_server: :default, nil, :read_only. All other
|
|
31
|
+
# shard names will cause the standard behavior to be used.
|
|
32
|
+
|
|
33
|
+
module Sequel
|
|
34
|
+
module ServerBlock
|
|
35
|
+
# Enable the server block on the connection pool, choosing the correct
|
|
36
|
+
# extension depending on whether the connection pool is threaded or not.
|
|
37
|
+
# Also defines the with_server method on the receiver for easy use.
|
|
38
|
+
def self.extended(db)
|
|
39
|
+
pool = db.pool
|
|
40
|
+
if defined?(ShardedThreadedConnectionPool) && pool.is_a?(ShardedThreadedConnectionPool)
|
|
41
|
+
pool.extend(ThreadedServerBlock)
|
|
42
|
+
pool.instance_variable_set(:@default_servers, {})
|
|
43
|
+
else
|
|
44
|
+
pool.extend(UnthreadedServerBlock)
|
|
45
|
+
pool.instance_variable_set(:@default_servers, [])
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Delegate to the connection pool
|
|
50
|
+
def with_server(server, &block)
|
|
51
|
+
pool.with_server(server, &block)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Adds with_server support for the sharded single connection pool.
|
|
56
|
+
module UnthreadedServerBlock
|
|
57
|
+
# Set a default server/shard to use inside the block.
|
|
58
|
+
def with_server(server)
|
|
59
|
+
begin
|
|
60
|
+
set_default_server(server)
|
|
61
|
+
yield
|
|
62
|
+
ensure
|
|
63
|
+
clear_default_server
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
# Make the given server the new default server.
|
|
70
|
+
def set_default_server(server)
|
|
71
|
+
@default_servers << server
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Remove the current default server, restoring the
|
|
75
|
+
# previous default server.
|
|
76
|
+
def clear_default_server
|
|
77
|
+
@default_servers.pop
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Use the server given to with_server if appropriate.
|
|
81
|
+
def pick_server(server)
|
|
82
|
+
if @default_servers.empty?
|
|
83
|
+
super
|
|
84
|
+
else
|
|
85
|
+
case server
|
|
86
|
+
when :default, nil, :read_only
|
|
87
|
+
@default_servers.last
|
|
88
|
+
else
|
|
89
|
+
super
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Adds with_server support for the sharded threaded connection pool.
|
|
96
|
+
module ThreadedServerBlock
|
|
97
|
+
# Set a default server/shard to use inside the block for the current
|
|
98
|
+
# thread.
|
|
99
|
+
def with_server(server)
|
|
100
|
+
begin
|
|
101
|
+
set_default_server(server)
|
|
102
|
+
yield
|
|
103
|
+
ensure
|
|
104
|
+
clear_default_server
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
private
|
|
109
|
+
|
|
110
|
+
# Make the given server the new default server for the current thread.
|
|
111
|
+
def set_default_server(server)
|
|
112
|
+
sync{(@default_servers[Thread.current] ||= [])} << server
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Remove the current default server for the current thread, restoring the
|
|
116
|
+
# previous default server.
|
|
117
|
+
def clear_default_server
|
|
118
|
+
t = Thread.current
|
|
119
|
+
a = sync{@default_servers[t]}
|
|
120
|
+
a.pop
|
|
121
|
+
sync{@default_servers.delete(t)} if a.empty?
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Use the server given to with_server for the given thread, if appropriate.
|
|
125
|
+
def pick_server(server)
|
|
126
|
+
a = sync{@default_servers[Thread.current]}
|
|
127
|
+
if !a || a.empty?
|
|
128
|
+
super
|
|
129
|
+
else
|
|
130
|
+
case server
|
|
131
|
+
when :default, nil, :read_only
|
|
132
|
+
a.last
|
|
133
|
+
else
|
|
134
|
+
super
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|