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
data/lib/sequel/dataset.rb
CHANGED
|
@@ -26,6 +26,14 @@ module Sequel
|
|
|
26
26
|
extend Metaprogramming
|
|
27
27
|
include Metaprogramming
|
|
28
28
|
include Enumerable
|
|
29
|
+
include SQL::AliasMethods
|
|
30
|
+
include SQL::BooleanMethods
|
|
31
|
+
include SQL::CastMethods
|
|
32
|
+
include SQL::ComplexExpressionMethods
|
|
33
|
+
include SQL::InequalityMethods
|
|
34
|
+
include SQL::NumericMethods
|
|
35
|
+
include SQL::OrderMethods
|
|
36
|
+
include SQL::StringMethods
|
|
29
37
|
end
|
|
30
38
|
|
|
31
39
|
require(%w"query actions features graph prepared_statements misc mutation sql", 'dataset')
|
data/lib/sequel/exceptions.rb
CHANGED
|
@@ -44,6 +44,10 @@ module Sequel
|
|
|
44
44
|
# and won't reraise it.
|
|
45
45
|
class Rollback < Error ; end
|
|
46
46
|
|
|
47
|
+
# Exception that occurs when unbinding a dataset that has multiple different values
|
|
48
|
+
# for a given variable.
|
|
49
|
+
class UnbindDuplicate < Error; end
|
|
50
|
+
|
|
47
51
|
class Error
|
|
48
52
|
AdapterNotFound = Sequel::AdapterNotFound
|
|
49
53
|
InvalidOperation = Sequel::InvalidOperation
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# The pretty_table extension adds Sequel::Dataset#print and the
|
|
2
|
+
# Sequel::PrettyTable class for creating nice-looking plain-text
|
|
3
|
+
# tables.
|
|
4
|
+
|
|
5
|
+
module Sequel
|
|
6
|
+
module PrettyTable
|
|
7
|
+
# Prints nice-looking plain-text tables via puts
|
|
8
|
+
#
|
|
9
|
+
# +--+-------+
|
|
10
|
+
# |id|name |
|
|
11
|
+
# |--+-------|
|
|
12
|
+
# |1 |fasdfas|
|
|
13
|
+
# |2 |test |
|
|
14
|
+
# +--+-------+
|
|
15
|
+
def self.print(records, columns=nil)
|
|
16
|
+
puts string(records, columns)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Return the string that #print will print via puts.
|
|
20
|
+
def self.string(records, columns = nil) # records is an array of hashes
|
|
21
|
+
columns ||= records.first.keys.sort_by{|x|x.to_s}
|
|
22
|
+
sizes = column_sizes(records, columns)
|
|
23
|
+
sep_line = separator_line(columns, sizes)
|
|
24
|
+
|
|
25
|
+
array = [sep_line, header_line(columns, sizes), sep_line]
|
|
26
|
+
records.each {|r| array << data_line(columns, sizes, r)}
|
|
27
|
+
array << sep_line
|
|
28
|
+
array.join("\n")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
### Private Module Methods ###
|
|
32
|
+
|
|
33
|
+
# Hash of the maximum size of the value for each column
|
|
34
|
+
def self.column_sizes(records, columns) # :nodoc:
|
|
35
|
+
sizes = Hash.new {0}
|
|
36
|
+
columns.each do |c|
|
|
37
|
+
s = c.to_s.size
|
|
38
|
+
sizes[c.to_sym] = s if s > sizes[c.to_sym]
|
|
39
|
+
end
|
|
40
|
+
records.each do |r|
|
|
41
|
+
columns.each do |c|
|
|
42
|
+
s = r[c].to_s.size
|
|
43
|
+
sizes[c.to_sym] = s if s > sizes[c.to_sym]
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
sizes
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# String for each data line
|
|
50
|
+
def self.data_line(columns, sizes, record) # :nodoc:
|
|
51
|
+
'|' << columns.map {|c| format_cell(sizes[c], record[c])}.join('|') << '|'
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Format the value so it takes up exactly size characters
|
|
55
|
+
def self.format_cell(size, v) # :nodoc:
|
|
56
|
+
case v
|
|
57
|
+
when Bignum, Fixnum
|
|
58
|
+
"%#{size}d" % v
|
|
59
|
+
when Float
|
|
60
|
+
"%#{size}g" % v
|
|
61
|
+
else
|
|
62
|
+
"%-#{size}s" % v.to_s
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# String for header line
|
|
67
|
+
def self.header_line(columns, sizes) # :nodoc:
|
|
68
|
+
'|' << columns.map {|c| "%-#{sizes[c]}s" % c.to_s}.join('|') << '|'
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# String for separtor line
|
|
72
|
+
def self.separator_line(columns, sizes) # :nodoc:
|
|
73
|
+
'+' << columns.map {|c| '-' * sizes[c]}.join('+') << '+'
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private_class_method :column_sizes, :data_line, :format_cell, :header_line, :separator_line
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# The arbitrary_servers extension allows you to connect to arbitrary
|
|
2
|
+
# servers/shards that were not defined when you created the database.
|
|
3
|
+
# To use it, you first extend the Database's connection pool with the
|
|
4
|
+
# Sequel::ArbitraryServers module:
|
|
5
|
+
#
|
|
6
|
+
# Sequel.extension :arbitrary_servers
|
|
7
|
+
# DB.pool.extend Sequel::ArbitraryServers
|
|
8
|
+
#
|
|
9
|
+
# Then you can pass arbitrary connection options for the server/shard
|
|
10
|
+
# to use as a hash:
|
|
11
|
+
#
|
|
12
|
+
# DB[:table].server(:host=>'...', :database=>'...').all
|
|
13
|
+
#
|
|
14
|
+
# Because Sequel can never be sure that the connection will be reused,
|
|
15
|
+
# arbitrary connections are disconnected as soon as the outermost block
|
|
16
|
+
# that uses them exits. So this example uses the same connection:
|
|
17
|
+
#
|
|
18
|
+
# DB.transaction(:server=>{:host=>'...', :database=>'...'}) do |c|
|
|
19
|
+
# DB.transaction(:server=>{:host=>'...', :database=>'...'}) do |c2|
|
|
20
|
+
# # c == c2
|
|
21
|
+
# end
|
|
22
|
+
# end
|
|
23
|
+
#
|
|
24
|
+
# But this example does not:
|
|
25
|
+
#
|
|
26
|
+
# DB.transaction(:server=>{:host=>'...', :database=>'...'}) do |c|
|
|
27
|
+
# end
|
|
28
|
+
# DB.transaction(:server=>{:host=>'...', :database=>'...'}) do |c2|
|
|
29
|
+
# # c != c2
|
|
30
|
+
# end
|
|
31
|
+
#
|
|
32
|
+
# You can use this extension in conjunction with the server_block
|
|
33
|
+
# extension:
|
|
34
|
+
#
|
|
35
|
+
# DB.with_server(:host=>'...', :database=>'...') do
|
|
36
|
+
# DB.synchronize do
|
|
37
|
+
# # All of these use the host/database given to with_server
|
|
38
|
+
# DB[:table].insert(...)
|
|
39
|
+
# DB[:table].update(...)
|
|
40
|
+
# DB.tables
|
|
41
|
+
# DB[:table].all
|
|
42
|
+
# end
|
|
43
|
+
# end
|
|
44
|
+
#
|
|
45
|
+
# Anyone using this extension in conjunction with the server_block
|
|
46
|
+
# extension may want to do the following to so that you don't need
|
|
47
|
+
# to call synchronize separately:
|
|
48
|
+
#
|
|
49
|
+
# def DB.with_server(*)
|
|
50
|
+
# super{synchronize{yield}}
|
|
51
|
+
# end
|
|
52
|
+
#
|
|
53
|
+
# Note that this extension only works with the sharded threaded connection
|
|
54
|
+
# pool. If you are using the sharded single connection pool, you need
|
|
55
|
+
# to switch to the sharded threaded connection pool before using this
|
|
56
|
+
# extension.
|
|
57
|
+
|
|
58
|
+
module Sequel
|
|
59
|
+
module ArbitraryServers
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
# If server is a hash, create a new connection for
|
|
63
|
+
# it, and cache it first by thread and then server.
|
|
64
|
+
def acquire(thread, server)
|
|
65
|
+
if server.is_a?(Hash)
|
|
66
|
+
sync{@allocated[thread] ||= {}}[server] = make_new(server)
|
|
67
|
+
else
|
|
68
|
+
super
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# If server is a hash, the entry for it probably doesn't
|
|
73
|
+
# exist in the @allocated hash, so check for existence to
|
|
74
|
+
# avoid calling nil.[]
|
|
75
|
+
def owned_connection(thread, server)
|
|
76
|
+
if server.is_a?(Hash)
|
|
77
|
+
if a = sync{@allocated[thread]}
|
|
78
|
+
a[server]
|
|
79
|
+
end
|
|
80
|
+
else
|
|
81
|
+
super
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# If server is a hash, return it directly.
|
|
86
|
+
def pick_server(server)
|
|
87
|
+
if server.is_a?(Hash)
|
|
88
|
+
server
|
|
89
|
+
else
|
|
90
|
+
super
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# If server is a hash, delete the thread from the allocated
|
|
95
|
+
# connections for that server. Additionally, if this was the last thread
|
|
96
|
+
# using that server, delete the server from the @allocated hash.
|
|
97
|
+
def release(thread, conn, server)
|
|
98
|
+
if server.is_a?(Hash)
|
|
99
|
+
a = @allocated[thread]
|
|
100
|
+
a.delete(server)
|
|
101
|
+
@allocated.delete(thread) if a.empty?
|
|
102
|
+
@disconnection_proc.call(conn) if @disconnection_proc
|
|
103
|
+
else
|
|
104
|
+
super
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# The columns_introspection extension attempts to introspect the
|
|
2
|
+
# selected columns for a dataset before issuing a query. If it
|
|
3
|
+
# thinks it can guess correctly at the columns the query will use,
|
|
4
|
+
# it will return the columns without issuing a database query.
|
|
5
|
+
# This method is not fool-proof, it's possible that some databases
|
|
6
|
+
# will use column names that Sequel does not expect.
|
|
7
|
+
#
|
|
8
|
+
# To enable this for a single dataset, extend the dataset with
|
|
9
|
+
# Sequel::ColumnIntrospection. To enable this for all datasets, run:
|
|
10
|
+
#
|
|
11
|
+
# Sequel::Dataset.introspect_all_columns
|
|
12
|
+
|
|
13
|
+
module Sequel
|
|
14
|
+
module ColumnsIntrospection
|
|
15
|
+
# Attempt to guess the columns that will be returned
|
|
16
|
+
# if there are columns selected, in order to skip a database
|
|
17
|
+
# query to retrieve the columns. This should work with
|
|
18
|
+
# Symbols, SQL::Identifiers, SQL::QualifiedIdentifiers, and
|
|
19
|
+
# SQL::AliasedExpressions.
|
|
20
|
+
def columns
|
|
21
|
+
return @columns if @columns
|
|
22
|
+
return columns_without_introspection unless cols = opts[:select] and !cols.empty?
|
|
23
|
+
probable_columns = cols.map{|c| probable_column_name(c)}
|
|
24
|
+
if probable_columns.all?
|
|
25
|
+
@columns = probable_columns
|
|
26
|
+
else
|
|
27
|
+
columns_without_introspection
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
# Return the probable name of the column, or nil if one
|
|
34
|
+
# cannot be determined.
|
|
35
|
+
def probable_column_name(c)
|
|
36
|
+
case c
|
|
37
|
+
when Symbol
|
|
38
|
+
_, c, a = split_symbol(c)
|
|
39
|
+
(a || c).to_sym
|
|
40
|
+
when SQL::Identifier
|
|
41
|
+
c.value.to_sym
|
|
42
|
+
when SQL::QualifiedIdentifier
|
|
43
|
+
col = c.column
|
|
44
|
+
col.is_a?(SQL::Identifier) ? col.value.to_sym : col.to_sym
|
|
45
|
+
when SQL::AliasedExpression
|
|
46
|
+
a = c.aliaz
|
|
47
|
+
a.is_a?(SQL::Identifier) ? a.value.to_sym : a.to_sym
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
class Dataset
|
|
53
|
+
alias columns_without_introspection columns
|
|
54
|
+
|
|
55
|
+
# Enable column introspection for every dataset.
|
|
56
|
+
def self.introspect_all_columns
|
|
57
|
+
include ColumnsIntrospection
|
|
58
|
+
remove_method(:columns) if instance_methods(false).map{|x| x.to_s}.include?('columns')
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
# These are extensions to core classes that Sequel enables by default.
|
|
2
|
+
# They make using Sequel's DSL easier by adding methods to Array,
|
|
3
|
+
# Hash, String, and Symbol to add methods that return Sequel
|
|
4
|
+
# expression objects.
|
|
5
|
+
|
|
6
|
+
# This extension loads the core extensions.
|
|
7
|
+
def Sequel.core_extensions?
|
|
8
|
+
true
|
|
9
|
+
end
|
|
10
|
+
|
|
1
11
|
# Sequel extends +Array+ to add methods to implement the SQL DSL.
|
|
2
12
|
# Most of these methods require that the array not be empty and that it
|
|
3
13
|
# must consist solely of other arrays that have exactly two elements.
|
|
@@ -8,20 +18,7 @@ class Array
|
|
|
8
18
|
# ~[[:a, true]] # SQL: a IS NOT TRUE
|
|
9
19
|
# ~[[:a, 1], [:b, [2, 3]]] # SQL: a != 1 OR b NOT IN (2, 3)
|
|
10
20
|
def ~
|
|
11
|
-
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
# +true+ if the array is not empty and all of its elements are
|
|
15
|
-
# arrays of size 2, +false+ otherwise. This is used to determine if the array
|
|
16
|
-
# could be a specifier of conditions, used similarly to a hash
|
|
17
|
-
# but allowing for duplicate keys and a specific order.
|
|
18
|
-
#
|
|
19
|
-
# [].to_a.all_two_pairs? # => false
|
|
20
|
-
# [:a].to_a.all_two_pairs? # => false
|
|
21
|
-
# [[:b]].to_a.all_two_pairs? # => false
|
|
22
|
-
# [[:a, 1]].to_a.all_two_pairs? # => true
|
|
23
|
-
def all_two_pairs?
|
|
24
|
-
!empty? && all?{|i| (Array === i) && (i.length == 2)}
|
|
21
|
+
Sequel.~(self)
|
|
25
22
|
end
|
|
26
23
|
|
|
27
24
|
# Return a <tt>Sequel::SQL::CaseExpression</tt> with this array as the conditions and the given
|
|
@@ -59,7 +56,7 @@ class Array
|
|
|
59
56
|
# [[:a, true]].sql_expr # SQL: a IS TRUE
|
|
60
57
|
# [[:a, 1], [:b, [2, 3]]].sql_expr # SQL: a = 1 AND b IN (2, 3)
|
|
61
58
|
def sql_expr
|
|
62
|
-
|
|
59
|
+
Sequel.expr(self)
|
|
63
60
|
end
|
|
64
61
|
|
|
65
62
|
# Return a <tt>Sequel::SQL::BooleanExpression</tt> created from this array, matching none
|
|
@@ -68,7 +65,7 @@ class Array
|
|
|
68
65
|
# [[:a, true]].sql_negate # SQL: a IS NOT TRUE
|
|
69
66
|
# [[:a, 1], [:b, [2, 3]]].sql_negate # SQL: a != 1 AND b NOT IN (2, 3)
|
|
70
67
|
def sql_negate
|
|
71
|
-
|
|
68
|
+
Sequel.negate(self)
|
|
72
69
|
end
|
|
73
70
|
|
|
74
71
|
# Return a <tt>Sequel::SQL::BooleanExpression</tt> created from this array, matching any of the
|
|
@@ -77,10 +74,10 @@ class Array
|
|
|
77
74
|
# [[:a, true]].sql_or # SQL: a IS TRUE
|
|
78
75
|
# [[:a, 1], [:b, [2, 3]]].sql_or # SQL: a = 1 OR b IN (2, 3)
|
|
79
76
|
def sql_or
|
|
80
|
-
|
|
77
|
+
Sequel.or(self)
|
|
81
78
|
end
|
|
82
79
|
|
|
83
|
-
# Return a <tt>Sequel::SQL::
|
|
80
|
+
# Return a <tt>Sequel::SQL::StringExpression</tt> representing an SQL string made up of the
|
|
84
81
|
# concatenation of this array's elements. If an argument is passed
|
|
85
82
|
# it is used in between each element of the array in the SQL
|
|
86
83
|
# concatenation.
|
|
@@ -90,22 +87,7 @@ class Array
|
|
|
90
87
|
# [:a, 'b'].sql_string_join # SQL: a || 'b'
|
|
91
88
|
# ['a', :b].sql_string_join(' ') # SQL: 'a' || ' ' || b
|
|
92
89
|
def sql_string_join(joiner=nil)
|
|
93
|
-
|
|
94
|
-
args = zip([joiner]*length).flatten
|
|
95
|
-
args.pop
|
|
96
|
-
else
|
|
97
|
-
args = self
|
|
98
|
-
end
|
|
99
|
-
args = args.collect{|a| [Symbol, ::Sequel::SQL::Expression, ::Sequel::LiteralString, TrueClass, FalseClass, NilClass].any?{|c| a.is_a?(c)} ? a : a.to_s}
|
|
100
|
-
::Sequel::SQL::StringExpression.new(:'||', *args)
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
private
|
|
104
|
-
|
|
105
|
-
# Raise an error if this array is not made up all two element arrays, otherwise create a <tt>Sequel::SQL::BooleanExpression</tt> from this array.
|
|
106
|
-
def sql_expr_if_all_two_pairs(*args)
|
|
107
|
-
raise(Sequel::Error, 'Not all elements of the array are arrays of size 2, so it cannot be converted to an SQL expression') unless all_two_pairs?
|
|
108
|
-
::Sequel::SQL::BooleanExpression.from_value_pairs(self, *args)
|
|
90
|
+
Sequel.join(self, joiner)
|
|
109
91
|
end
|
|
110
92
|
end
|
|
111
93
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
# the user to easily group schema changes and migrate the database
|
|
3
3
|
# to a newer version or revert to a previous version.
|
|
4
4
|
|
|
5
|
+
#
|
|
5
6
|
module Sequel
|
|
6
7
|
# Sequel's older migration class, available for backward compatibility.
|
|
7
8
|
# Uses subclasses with up and down instance methods for each migration:
|
|
@@ -21,7 +22,7 @@ module Sequel
|
|
|
21
22
|
#
|
|
22
23
|
# Part of the +migration+ extension.
|
|
23
24
|
class Migration
|
|
24
|
-
#
|
|
25
|
+
# Set the database associated with this migration.
|
|
25
26
|
def initialize(db)
|
|
26
27
|
@db = db
|
|
27
28
|
end
|
|
@@ -42,6 +43,11 @@ module Sequel
|
|
|
42
43
|
def self.inherited(base)
|
|
43
44
|
descendants << base
|
|
44
45
|
end
|
|
46
|
+
|
|
47
|
+
# Don't allow transaction overriding in old migrations.
|
|
48
|
+
def self.use_transactions
|
|
49
|
+
nil
|
|
50
|
+
end
|
|
45
51
|
|
|
46
52
|
# The default down action does nothing
|
|
47
53
|
def down
|
|
@@ -68,6 +74,15 @@ module Sequel
|
|
|
68
74
|
# Proc used for the up action
|
|
69
75
|
attr_accessor :up
|
|
70
76
|
|
|
77
|
+
# Whether to use transactions for this migration, default depends on the
|
|
78
|
+
# database.
|
|
79
|
+
attr_accessor :use_transactions
|
|
80
|
+
|
|
81
|
+
# Don't set transaction use by default.
|
|
82
|
+
def initialize
|
|
83
|
+
@use_transactions = nil
|
|
84
|
+
end
|
|
85
|
+
|
|
71
86
|
# Apply the appropriate block on the +Database+
|
|
72
87
|
# instance using instance_eval.
|
|
73
88
|
def apply(db, direction)
|
|
@@ -99,6 +114,16 @@ module Sequel
|
|
|
99
114
|
migration.down = block
|
|
100
115
|
end
|
|
101
116
|
|
|
117
|
+
# Disable the use of transactions for the related migration
|
|
118
|
+
def no_transaction
|
|
119
|
+
migration.use_transactions = false
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Enable the use of transactions for the related migration
|
|
123
|
+
def transaction
|
|
124
|
+
migration.use_transactions = true
|
|
125
|
+
end
|
|
126
|
+
|
|
102
127
|
# Defines the migration's up action.
|
|
103
128
|
def up(&block)
|
|
104
129
|
migration.up = block
|
|
@@ -165,6 +190,10 @@ module Sequel
|
|
|
165
190
|
@actions << [:alter_table, table, MigrationAlterTableReverser.new.reverse(&block)]
|
|
166
191
|
end
|
|
167
192
|
|
|
193
|
+
def create_join_table(*args)
|
|
194
|
+
@actions << [:drop_join_table, *args]
|
|
195
|
+
end
|
|
196
|
+
|
|
168
197
|
def create_table(*args)
|
|
169
198
|
@actions << [:drop_table, args.first]
|
|
170
199
|
end
|
|
@@ -302,7 +331,7 @@ module Sequel
|
|
|
302
331
|
#
|
|
303
332
|
# Part of the +migration+ extension.
|
|
304
333
|
class Migrator
|
|
305
|
-
MIGRATION_FILE_PATTERN = /\A\d+_.+\.rb\z/i.freeze
|
|
334
|
+
MIGRATION_FILE_PATTERN = /\A(\d+)_.+\.rb\z/i.freeze
|
|
306
335
|
MIGRATION_SPLITTER = '_'.freeze
|
|
307
336
|
MINIMUM_TIMESTAMP = 20000101
|
|
308
337
|
|
|
@@ -311,11 +340,28 @@ module Sequel
|
|
|
311
340
|
class Error < Sequel::Error
|
|
312
341
|
end
|
|
313
342
|
|
|
343
|
+
# Exception class raised when Migrator.check_current signals that it is
|
|
344
|
+
# not current.
|
|
345
|
+
class NotCurrentError < Error
|
|
346
|
+
end
|
|
347
|
+
|
|
314
348
|
# Wrapper for +run+, maintaining backwards API compatibility
|
|
315
349
|
def self.apply(db, directory, target = nil, current = nil)
|
|
316
350
|
run(db, directory, :target => target, :current => current)
|
|
317
351
|
end
|
|
318
352
|
|
|
353
|
+
# Raise a NotCurrentError unless the migrator is current, takes the same
|
|
354
|
+
# arguments as #run.
|
|
355
|
+
def self.check_current(*args)
|
|
356
|
+
raise(NotCurrentError, 'migrator is not current') unless is_current?(*args)
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
# Return whether the migrator is current (i.e. it does not need to make
|
|
360
|
+
# any changes). Takes the same arguments as #run.
|
|
361
|
+
def self.is_current?(db, directory, opts={})
|
|
362
|
+
migrator_class(directory).new(db, directory, opts).is_current?
|
|
363
|
+
end
|
|
364
|
+
|
|
319
365
|
# Migrates the supplied database using the migration files in the the specified directory. Options:
|
|
320
366
|
# * :column :: The column in the :table argument storing the migration version (default: :version).
|
|
321
367
|
# * :current :: The current version of the database. If not given, it is retrieved from the database
|
|
@@ -336,11 +382,15 @@ module Sequel
|
|
|
336
382
|
# if the version number appears to be a unix time integer for a year
|
|
337
383
|
# after 2005, otherwise uses the IntegerMigrator.
|
|
338
384
|
def self.migrator_class(directory)
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
385
|
+
if self.equal?(Migrator)
|
|
386
|
+
Dir.new(directory).each do |file|
|
|
387
|
+
next unless MIGRATION_FILE_PATTERN.match(file)
|
|
388
|
+
return TimestampMigrator if file.split(MIGRATION_SPLITTER, 2).first.to_i > MINIMUM_TIMESTAMP
|
|
389
|
+
end
|
|
390
|
+
IntegerMigrator
|
|
391
|
+
else
|
|
392
|
+
self
|
|
342
393
|
end
|
|
343
|
-
IntegerMigrator
|
|
344
394
|
end
|
|
345
395
|
private_class_method :migrator_class
|
|
346
396
|
|
|
@@ -375,13 +425,35 @@ module Sequel
|
|
|
375
425
|
@db = db
|
|
376
426
|
@directory = directory
|
|
377
427
|
@files = get_migration_files
|
|
378
|
-
|
|
428
|
+
schema, table = @db.send(:schema_and_table, opts[:table] || self.class.const_get(:DEFAULT_SCHEMA_TABLE))
|
|
429
|
+
@table = schema ? Sequel::SQL::QualifiedIdentifier.new(schema, table) : table
|
|
379
430
|
@column = opts[:column] || self.class.const_get(:DEFAULT_SCHEMA_COLUMN)
|
|
380
431
|
@ds = schema_dataset
|
|
432
|
+
@use_transactions = opts[:use_transactions]
|
|
381
433
|
end
|
|
382
434
|
|
|
383
435
|
private
|
|
384
436
|
|
|
437
|
+
# If transactions should be used for the migration, yield to the block
|
|
438
|
+
# inside a transaction. Otherwise, just yield to the block.
|
|
439
|
+
def checked_transaction(migration, &block)
|
|
440
|
+
use_trans = if @use_transactions.nil?
|
|
441
|
+
if migration.use_transactions.nil?
|
|
442
|
+
@db.supports_transactional_ddl?
|
|
443
|
+
else
|
|
444
|
+
migration.use_transactions
|
|
445
|
+
end
|
|
446
|
+
else
|
|
447
|
+
@use_transactions
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
if use_trans
|
|
451
|
+
db.transaction(&block)
|
|
452
|
+
else
|
|
453
|
+
yield
|
|
454
|
+
end
|
|
455
|
+
end
|
|
456
|
+
|
|
385
457
|
# Remove all migration classes. Done by the migrator to ensure that
|
|
386
458
|
# the correct migration classes are picked up.
|
|
387
459
|
def remove_migration_classes
|
|
@@ -423,19 +495,24 @@ module Sequel
|
|
|
423
495
|
@current = opts[:current] || current_migration_version
|
|
424
496
|
|
|
425
497
|
raise(Error, "No current version available") unless current
|
|
426
|
-
raise(Error, "No target version available") unless target
|
|
498
|
+
raise(Error, "No target version available, probably because no migration files found or filenames don't follow the migration filename convention") unless target
|
|
427
499
|
|
|
428
500
|
@direction = current < target ? :up : :down
|
|
429
501
|
@migrations = get_migrations
|
|
430
502
|
end
|
|
431
503
|
|
|
504
|
+
# The integer migrator is current if the current version is the same as the target version.
|
|
505
|
+
def is_current?
|
|
506
|
+
current_migration_version == target
|
|
507
|
+
end
|
|
508
|
+
|
|
432
509
|
# Apply all migrations on the database
|
|
433
510
|
def run
|
|
434
511
|
migrations.zip(version_numbers).each do |m, v|
|
|
435
512
|
t = Time.now
|
|
436
513
|
lv = up? ? v : v + 1
|
|
437
514
|
db.log_info("Begin applying migration version #{lv}, direction: #{direction}")
|
|
438
|
-
|
|
515
|
+
checked_transaction(m) do
|
|
439
516
|
m.apply(db, direction)
|
|
440
517
|
set_migration_version(v)
|
|
441
518
|
end
|
|
@@ -459,6 +536,9 @@ module Sequel
|
|
|
459
536
|
Dir.new(directory).each do |file|
|
|
460
537
|
next unless MIGRATION_FILE_PATTERN.match(file)
|
|
461
538
|
version = migration_version_from_file(file)
|
|
539
|
+
if version >= 20000101
|
|
540
|
+
raise Migrator::Error, "Migration number too large, must use TimestampMigrator: #{file}"
|
|
541
|
+
end
|
|
462
542
|
raise(Error, "Duplicate migration version: #{version}") if files[version]
|
|
463
543
|
files[version] = File.join(directory, file)
|
|
464
544
|
end
|
|
@@ -543,12 +623,18 @@ module Sequel
|
|
|
543
623
|
@migration_tuples = get_migration_tuples
|
|
544
624
|
end
|
|
545
625
|
|
|
626
|
+
# The timestamp migrator is current if there are no migrations to apply
|
|
627
|
+
# in either direction.
|
|
628
|
+
def is_current?
|
|
629
|
+
migration_tuples.empty?
|
|
630
|
+
end
|
|
631
|
+
|
|
546
632
|
# Apply all migration tuples on the database
|
|
547
633
|
def run
|
|
548
634
|
migration_tuples.each do |m, f, direction|
|
|
549
635
|
t = Time.now
|
|
550
636
|
db.log_info("Begin applying migration #{f}, direction: #{direction}")
|
|
551
|
-
|
|
637
|
+
checked_transaction(m) do
|
|
552
638
|
m.apply(db, direction)
|
|
553
639
|
fi = f.downcase
|
|
554
640
|
direction == :up ? ds.insert(column=>fi) : ds.filter(column=>fi).delete
|
|
@@ -588,7 +674,7 @@ module Sequel
|
|
|
588
674
|
next unless MIGRATION_FILE_PATTERN.match(file)
|
|
589
675
|
files << File.join(directory, file)
|
|
590
676
|
end
|
|
591
|
-
files.
|
|
677
|
+
files.sort_by{|f| MIGRATION_FILE_PATTERN.match(File.basename(f))[1].to_i}
|
|
592
678
|
end
|
|
593
679
|
|
|
594
680
|
# Returns tuples of migration, filename, and direction
|
|
@@ -21,6 +21,11 @@
|
|
|
21
21
|
# Then, before data is stored in the database, it is converted to New
|
|
22
22
|
# York time. When data is retrieved from the database, it is
|
|
23
23
|
# converted to Los Angeles time.
|
|
24
|
+
#
|
|
25
|
+
# Note that typecasting from the database timezone to the application
|
|
26
|
+
# timezone when fetching rows is dependent on the database adapter,
|
|
27
|
+
# and only works on adapters where Sequel itself does the conversion.
|
|
28
|
+
# It should work on mysql, postgres, sqlite, ibmdb, and jdbc.
|
|
24
29
|
|
|
25
30
|
require 'tzinfo'
|
|
26
31
|
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# The null_dataset extension adds the Dataset#nullify method, which
|
|
2
|
+
# returns a cloned dataset that will never issue a query to the
|
|
3
|
+
# database. It implements the null object pattern for datasets.
|
|
4
|
+
#
|
|
5
|
+
# The most common usage is probably in a method that must return
|
|
6
|
+
# a dataset, where the method knows the dataset shouldn't return
|
|
7
|
+
# anything. With standard Sequel, you'd probably just add a
|
|
8
|
+
# WHERE condition that is always false, but that still results
|
|
9
|
+
# in a query being sent to the database, and can be overridden
|
|
10
|
+
# using #unfiltered, the OR operator, or a UNION.
|
|
11
|
+
#
|
|
12
|
+
# Usage:
|
|
13
|
+
#
|
|
14
|
+
# ds = DB[:items].nullify.where(:a=>:b).select(:c)
|
|
15
|
+
# ds.sql # => "SELECT c FROM items WHERE (a = b)"
|
|
16
|
+
# ds.all # => [] # no query sent to the database
|
|
17
|
+
#
|
|
18
|
+
# Note that there is one case where a null dataset will sent
|
|
19
|
+
# a query to the database. If you call #columns on a nulled
|
|
20
|
+
# dataset and the dataset doesn't have an already cached
|
|
21
|
+
# version of the columns, it will create a new dataset with
|
|
22
|
+
# the same options to get the columns.
|
|
23
|
+
|
|
24
|
+
module Sequel
|
|
25
|
+
class Dataset
|
|
26
|
+
module NullDataset
|
|
27
|
+
# Create a new dataset from the dataset (which won't
|
|
28
|
+
# be nulled) to get the columns if they aren't already cached.
|
|
29
|
+
def columns
|
|
30
|
+
@columns ||= db.dataset(@opts).columns
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Return 0 without sending a database query.
|
|
34
|
+
def delete
|
|
35
|
+
0
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Return self without sending a database query, never yielding.
|
|
39
|
+
def each
|
|
40
|
+
self
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Return nil without sending a database query, never yielding.
|
|
44
|
+
def fetch_rows(sql)
|
|
45
|
+
nil
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Return nil without sending a database query.
|
|
49
|
+
def insert(*)
|
|
50
|
+
nil
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Return nil without sending a database query.
|
|
54
|
+
def truncate
|
|
55
|
+
nil
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Return 0 without sending a database query.
|
|
59
|
+
def update(v={})
|
|
60
|
+
0
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
protected
|
|
64
|
+
|
|
65
|
+
# Return nil without sending a database query.
|
|
66
|
+
def _import(columns, values, opts)
|
|
67
|
+
nil
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
# Just in case these are called directly by some internal code,
|
|
73
|
+
# make them noops. There's nothing we can do if the db
|
|
74
|
+
# is accessed directly to make a change, though.
|
|
75
|
+
(%w'_ddl _dui _insert' << '').each do |m|
|
|
76
|
+
class_eval("private; def execute#{m}(sql, opts={}) end", __FILE__, __LINE__)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Return a cloned nullified dataset.
|
|
81
|
+
def nullify
|
|
82
|
+
clone.nullify!
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Nullify the current dataset
|
|
86
|
+
def nullify!
|
|
87
|
+
extend NullDataset
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|