sequel 4.21.0 → 4.22.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.
Files changed (104) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +32 -0
  3. data/README.rdoc +3 -4
  4. data/doc/opening_databases.rdoc +10 -75
  5. data/doc/release_notes/4.22.0.txt +72 -0
  6. data/lib/sequel/adapters/ado/access.rb +1 -1
  7. data/lib/sequel/adapters/cubrid.rb +3 -3
  8. data/lib/sequel/adapters/db2.rb +1 -0
  9. data/lib/sequel/adapters/dbi.rb +1 -0
  10. data/lib/sequel/adapters/fdbsql.rb +3 -2
  11. data/lib/sequel/adapters/firebird.rb +1 -0
  12. data/lib/sequel/adapters/ibmdb.rb +1 -21
  13. data/lib/sequel/adapters/informix.rb +1 -0
  14. data/lib/sequel/adapters/jdbc.rb +37 -49
  15. data/lib/sequel/adapters/jdbc/fdbsql.rb +1 -0
  16. data/lib/sequel/adapters/mysql.rb +5 -3
  17. data/lib/sequel/adapters/mysql2.rb +5 -2
  18. data/lib/sequel/adapters/odbc.rb +8 -4
  19. data/lib/sequel/adapters/openbase.rb +1 -0
  20. data/lib/sequel/adapters/oracle.rb +3 -46
  21. data/lib/sequel/adapters/postgres.rb +3 -36
  22. data/lib/sequel/adapters/shared/access.rb +1 -1
  23. data/lib/sequel/adapters/shared/fdbsql.rb +3 -3
  24. data/lib/sequel/adapters/shared/mssql.rb +1 -1
  25. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +12 -44
  26. data/lib/sequel/adapters/shared/oracle.rb +6 -2
  27. data/lib/sequel/adapters/shared/postgres.rb +6 -6
  28. data/lib/sequel/adapters/shared/sqlite.rb +1 -1
  29. data/lib/sequel/adapters/sqlite.rb +3 -46
  30. data/lib/sequel/adapters/tinytds.rb +12 -28
  31. data/lib/sequel/adapters/utils/pg_types.rb +1 -1
  32. data/lib/sequel/connection_pool/sharded_threaded.rb +63 -16
  33. data/lib/sequel/connection_pool/threaded.rb +72 -18
  34. data/lib/sequel/core.rb +1 -1
  35. data/lib/sequel/database/connecting.rb +2 -2
  36. data/lib/sequel/database/misc.rb +5 -5
  37. data/lib/sequel/database/query.rb +3 -2
  38. data/lib/sequel/database/schema_generator.rb +19 -19
  39. data/lib/sequel/database/schema_methods.rb +2 -2
  40. data/lib/sequel/database/transactions.rb +3 -3
  41. data/lib/sequel/dataset/actions.rb +18 -8
  42. data/lib/sequel/dataset/graph.rb +2 -2
  43. data/lib/sequel/dataset/prepared_statements.rb +28 -1
  44. data/lib/sequel/dataset/query.rb +7 -7
  45. data/lib/sequel/exceptions.rb +27 -24
  46. data/lib/sequel/extensions/_pretty_table.rb +1 -1
  47. data/lib/sequel/extensions/constraint_validations.rb +2 -2
  48. data/lib/sequel/extensions/date_arithmetic.rb +2 -2
  49. data/lib/sequel/extensions/pg_array.rb +10 -1
  50. data/lib/sequel/extensions/pg_row.rb +1 -1
  51. data/lib/sequel/extensions/pg_static_cache_updater.rb +1 -1
  52. data/lib/sequel/extensions/schema_dumper.rb +8 -8
  53. data/lib/sequel/extensions/split_array_nil.rb +1 -1
  54. data/lib/sequel/model.rb +1 -1
  55. data/lib/sequel/model/associations.rb +18 -11
  56. data/lib/sequel/model/base.rb +15 -15
  57. data/lib/sequel/model/exceptions.rb +11 -2
  58. data/lib/sequel/plugins/accessed_columns.rb +1 -1
  59. data/lib/sequel/plugins/auto_validations.rb +1 -1
  60. data/lib/sequel/plugins/boolean_readers.rb +1 -1
  61. data/lib/sequel/plugins/class_table_inheritance.rb +4 -7
  62. data/lib/sequel/plugins/composition.rb +1 -1
  63. data/lib/sequel/plugins/constraint_validations.rb +2 -2
  64. data/lib/sequel/plugins/csv_serializer.rb +171 -0
  65. data/lib/sequel/plugins/dirty.rb +2 -2
  66. data/lib/sequel/plugins/hook_class_methods.rb +1 -1
  67. data/lib/sequel/plugins/instance_hooks.rb +1 -1
  68. data/lib/sequel/plugins/many_through_many.rb +1 -1
  69. data/lib/sequel/plugins/nested_attributes.rb +5 -5
  70. data/lib/sequel/plugins/pg_array_associations.rb +4 -4
  71. data/lib/sequel/plugins/prepared_statements.rb +2 -2
  72. data/lib/sequel/plugins/prepared_statements_safe.rb +1 -1
  73. data/lib/sequel/plugins/serialization.rb +6 -6
  74. data/lib/sequel/plugins/serialization_modification_detection.rb +1 -1
  75. data/lib/sequel/plugins/sharding.rb +3 -1
  76. data/lib/sequel/plugins/single_table_inheritance.rb +5 -13
  77. data/lib/sequel/plugins/static_cache.rb +2 -2
  78. data/lib/sequel/plugins/tactical_eager_loading.rb +1 -1
  79. data/lib/sequel/plugins/tree.rb +1 -1
  80. data/lib/sequel/plugins/validation_class_methods.rb +2 -2
  81. data/lib/sequel/plugins/validation_helpers.rb +4 -4
  82. data/lib/sequel/plugins/xml_serializer.rb +3 -3
  83. data/lib/sequel/sql.rb +1 -1
  84. data/lib/sequel/version.rb +1 -1
  85. data/spec/adapters/postgres_spec.rb +17 -0
  86. data/spec/core/connection_pool_spec.rb +1 -1
  87. data/spec/core/dataset_spec.rb +22 -0
  88. data/spec/extensions/auto_validations_spec.rb +1 -1
  89. data/spec/extensions/blacklist_security_spec.rb +2 -2
  90. data/spec/extensions/csv_serializer_spec.rb +173 -0
  91. data/spec/extensions/json_serializer_spec.rb +2 -2
  92. data/spec/extensions/nested_attributes_spec.rb +9 -9
  93. data/spec/extensions/pg_array_spec.rb +5 -0
  94. data/spec/extensions/single_table_inheritance_spec.rb +21 -0
  95. data/spec/extensions/touch_spec.rb +1 -1
  96. data/spec/extensions/tree_spec.rb +4 -0
  97. data/spec/extensions/xml_serializer_spec.rb +3 -3
  98. data/spec/integration/prepared_statement_test.rb +1 -1
  99. data/spec/integration/schema_test.rb +7 -0
  100. data/spec/integration/type_test.rb +2 -2
  101. data/spec/model/associations_spec.rb +108 -14
  102. data/spec/model/base_spec.rb +8 -8
  103. data/spec/model/record_spec.rb +7 -7
  104. metadata +6 -2
@@ -119,7 +119,7 @@ module Sequel
119
119
  # :no_index :: Set to true not to create the second index.
120
120
  # :no_primary_key :: Set to true to not create the primary key.
121
121
  def create_join_table(hash, options=OPTS)
122
- keys = hash.keys.sort_by{|k| k.to_s}
122
+ keys = hash.keys.sort_by(&:to_s)
123
123
  create_table(join_table_name(hash, options), options) do
124
124
  keys.each do |key|
125
125
  v = hash[key]
@@ -781,7 +781,7 @@ module Sequel
781
781
  options[:name]
782
782
  else
783
783
  table_names = entries.map{|e| join_table_name_extract(e)}
784
- table_names.map{|t| t.to_s}.sort.join('_')
784
+ table_names.map(&:to_s).sort.join('_')
785
785
  end
786
786
  end
787
787
 
@@ -80,7 +80,7 @@ module Sequel
80
80
  tot_retries = opts.fetch(:num_retries, 5)
81
81
  num_retries = 0 unless tot_retries.nil?
82
82
  begin
83
- transaction(opts.merge(:retry_on=>nil, :retrying=>true), &block)
83
+ transaction(Hash[opts].merge!(:retry_on=>nil, :retrying=>true), &block)
84
84
  rescue *retry_on => e
85
85
  if num_retries
86
86
  num_retries += 1
@@ -100,7 +100,7 @@ module Sequel
100
100
  raise Sequel::Error, "cannot set :retry_on options if you are already inside a transaction"
101
101
  end
102
102
  if opts[:savepoint] != false && (stack = _trans(conn)[:savepoints]) && stack.last
103
- _transaction(conn, opts.merge(:savepoint=>true), &block)
103
+ _transaction(conn, Hash[opts].merge!(:savepoint=>true), &block)
104
104
  else
105
105
  return yield(conn)
106
106
  end
@@ -277,7 +277,7 @@ module Sequel
277
277
  callbacks = _trans(conn)[committed ? :after_commit : :after_rollback]
278
278
  Sequel.synchronize{@transactions.delete(conn)}
279
279
  if callbacks
280
- callbacks.each{|b| b.call}
280
+ callbacks.each(&:call)
281
281
  end
282
282
  end
283
283
  end
@@ -8,7 +8,7 @@ module Sequel
8
8
  # ---------------------
9
9
 
10
10
  # Action methods defined by Sequel that execute code on the database.
11
- ACTION_METHODS = (<<-METHS).split.map{|x| x.to_sym}
11
+ ACTION_METHODS = (<<-METHS).split.map(&:to_sym)
12
12
  << [] all avg count columns columns! delete each
13
13
  empty? fetch_rows first first! get import insert interval last
14
14
  map max min multi_insert paged_each range select_hash select_hash_groups select_map select_order_map
@@ -493,7 +493,8 @@ module Sequel
493
493
  total_limit = @opts[:limit]
494
494
  offset = @opts[:offset]
495
495
  if server = @opts[:server]
496
- opts = opts.merge(:server=>server)
496
+ opts = Hash[opts]
497
+ opts[:server] = server
497
498
  end
498
499
 
499
500
  rows_per_fetch = opts[:rows_per_fetch] || 1000
@@ -701,7 +702,7 @@ module Sequel
701
702
  end
702
703
  end
703
704
  elsif key_column.is_a?(Array)
704
- each{|r| h[r.values_at(*key_column)] = r}
705
+ each{|r| h[key_column.map{|k| r[k]}] = r}
705
706
  else
706
707
  each{|r| h[r[key_column]] = r}
707
708
  end
@@ -744,7 +745,7 @@ module Sequel
744
745
  end
745
746
  end
746
747
  elsif key_column.is_a?(Array)
747
- each{|r| (h[r.values_at(*key_column)] ||= []) << r}
748
+ each{|r| (h[key_column.map{|k| r[k]}] ||= []) << r}
748
749
  else
749
750
  each{|r| (h[r[key_column]] ||= []) << r}
750
751
  end
@@ -833,7 +834,7 @@ module Sequel
833
834
  # separate insert commands for each row. Otherwise, call #multi_insert_sql
834
835
  # and execute each statement it gives separately.
835
836
  def _import(columns, values, opts)
836
- trans_opts = opts.merge(:server=>@opts[:server])
837
+ trans_opts = Hash[opts].merge!(:server=>@opts[:server])
837
838
  if opts[:return] == :primary_key
838
839
  @db.transaction(trans_opts){values.map{|v| insert(columns, v)}}
839
840
  else
@@ -901,14 +902,23 @@ module Sequel
901
902
 
902
903
  # Set the server to use to :default unless it is already set in the passed opts
903
904
  def default_server_opts(opts)
904
- @db.sharded? ? {:server=>@opts[:server] || :default}.merge(opts) : opts
905
+ if @db.sharded?
906
+ opts = Hash[opts]
907
+ opts[:server] = @opts[:server] || :default
908
+ end
909
+ opts
905
910
  end
906
911
 
907
912
  # Execute the given select SQL on the database using execute. Use the
908
913
  # :read_only server unless a specific server is set.
909
914
  def execute(sql, opts=OPTS, &block)
910
915
  db = @db
911
- db.execute(sql, db.sharded? ? {:server=>@opts[:server] || :read_only}.merge(opts) : opts, &block)
916
+ if db.sharded?
917
+ opts = Hash[opts]
918
+ opts[:server] = @opts[:server] || :read_only
919
+ opts
920
+ end
921
+ db.execute(sql, opts, &block)
912
922
  end
913
923
 
914
924
  # Execute the given SQL on the database using execute_ddl.
@@ -982,7 +992,7 @@ module Sequel
982
992
  [v, descending]
983
993
  end
984
994
 
985
- row_values = yield(row, order_exprs.map{|e| e.first})
995
+ row_values = yield(row, order_exprs.map(&:first))
986
996
 
987
997
  last_expr = []
988
998
  cond = order_exprs.zip(row_values).map do |(v, descending), value|
@@ -18,7 +18,7 @@ module Sequel
18
18
  raise Error, "cannot call add_graph_aliases on a dataset that has not been called with graph or set_graph_aliases"
19
19
  end
20
20
  columns, graph_aliases = graph_alias_columns(graph_aliases)
21
- select_more(*columns).clone(:graph_aliases => ga.merge(graph_aliases))
21
+ select_more(*columns).clone(:graph_aliases => Hash[ga].merge!(graph_aliases))
22
22
  end
23
23
 
24
24
  # Similar to Dataset#join_table, but uses unambiguous aliases for selected
@@ -72,7 +72,7 @@ module Sequel
72
72
  when SQL::QualifiedIdentifier
73
73
  table_alias ||= split_qualifiers(table).last
74
74
  when SQL::AliasedExpression
75
- return graph(table.expression, join_conditions, {:table_alias=>table.alias}.merge(options), &block)
75
+ return graph(table.expression, join_conditions, {:table_alias=>table.alias}.merge!(options), &block)
76
76
  else
77
77
  raise Error, "The dataset argument should be a symbol or dataset"
78
78
  end
@@ -7,6 +7,33 @@ module Sequel
7
7
  # ---------------------
8
8
 
9
9
  PREPARED_ARG_PLACEHOLDER = LiteralString.new('?').freeze
10
+
11
+ DEFAULT_PREPARED_STATEMENT_MODULE_METHODS = %w'execute execute_dui execute_insert'.freeze.each(&:freeze)
12
+ PREPARED_STATEMENT_MODULE_CODE = {
13
+ :bind => "opts = Hash[opts]; opts[:arguments] = bind_arguments".freeze,
14
+ :prepare => "sql = prepared_statement_name".freeze,
15
+ :prepare_bind => "sql = prepared_statement_name; opts = Hash[opts]; opts[:arguments] = bind_arguments".freeze
16
+ }.freeze
17
+
18
+ def self.prepared_statements_module(code, mods, meths=DEFAULT_PREPARED_STATEMENT_MODULE_METHODS, &block)
19
+ code = PREPARED_STATEMENT_MODULE_CODE[code] || code
20
+
21
+ Module.new do
22
+ Array(mods).each do |mod|
23
+ include mod
24
+ end
25
+
26
+ if block
27
+ module_eval(&block)
28
+ end
29
+
30
+ meths.each do |meth|
31
+ module_eval("def #{meth}(sql, opts=Sequel::OPTS) #{code}; super end", __FILE__, __LINE__)
32
+ end
33
+ private *meths
34
+ end
35
+ end
36
+ private_class_method :prepared_statements_module
10
37
 
11
38
  # Default implementation of the argument mapper to allow
12
39
  # native database support for bind variables and prepared
@@ -221,7 +248,7 @@ module Sequel
221
248
  # # SELECT * FROM table WHERE id = ? LIMIT 1 -- (1)
222
249
  # # => {:id=>1}
223
250
  def bind(bind_vars={})
224
- clone(:bind_vars=>@opts[:bind_vars] ? @opts[:bind_vars].merge(bind_vars) : bind_vars)
251
+ clone(:bind_vars=>@opts[:bind_vars] ? Hash[@opts[:bind_vars]].merge!(bind_vars) : bind_vars)
225
252
  end
226
253
 
227
254
  # For the given type (:select, :first, :insert, :insert_select, :update, or :delete),
@@ -32,7 +32,7 @@ module Sequel
32
32
  JOIN_METHODS = (CONDITIONED_JOIN_TYPES + UNCONDITIONED_JOIN_TYPES).map{|x| "#{x}_join".to_sym} + [:join, :join_table]
33
33
 
34
34
  # Methods that return modified datasets
35
- QUERY_METHODS = (<<-METHS).split.map{|x| x.to_sym} + JOIN_METHODS
35
+ QUERY_METHODS = (<<-METHS).split.map(&:to_sym) + JOIN_METHODS
36
36
  add_graph_aliases and distinct except exclude exclude_having exclude_where
37
37
  filter for_update from from_self graph grep group group_and_count group_by having intersect invert
38
38
  limit lock_style naked offset or order order_append order_by order_more order_prepend qualify
@@ -74,10 +74,10 @@ module Sequel
74
74
  def clone(opts = nil)
75
75
  c = super()
76
76
  if opts
77
- c.instance_variable_set(:@opts, @opts.merge(opts))
77
+ c.instance_variable_set(:@opts, Hash[@opts].merge!(opts))
78
78
  c.instance_variable_set(:@columns, nil) if @columns && !opts.each_key{|o| break if COLUMN_CHANGE_OPTS.include?(o)}
79
79
  else
80
- c.instance_variable_set(:@opts, @opts.dup)
80
+ c.instance_variable_set(:@opts, Hash[@opts])
81
81
  end
82
82
  c
83
83
  end
@@ -584,7 +584,7 @@ module Sequel
584
584
  # Returns a cloned dataset without a row_proc.
585
585
  #
586
586
  # ds = DB[:items]
587
- # ds.row_proc = proc{|r| r.invert}
587
+ # ds.row_proc = proc(&:invert)
588
588
  # ds.all # => [{2=>:id}]
589
589
  # ds.naked.all # => [{:id=>2}]
590
590
  def naked
@@ -939,7 +939,7 @@ module Sequel
939
939
  s, ds = hoist_cte(dataset)
940
940
  s.with(name, ds, opts)
941
941
  else
942
- clone(:with=>(@opts[:with]||[]) + [opts.merge(:name=>name, :dataset=>dataset)])
942
+ clone(:with=>(@opts[:with]||[]) + [Hash[opts].merge!(:name=>name, :dataset=>dataset)])
943
943
  end
944
944
  end
945
945
 
@@ -968,7 +968,7 @@ module Sequel
968
968
  s, ds = hoist_cte(recursive)
969
969
  s.with_recursive(name, nonrecursive, ds, opts)
970
970
  else
971
- clone(:with=>(@opts[:with]||[]) + [opts.merge(:recursive=>true, :name=>name, :dataset=>nonrecursive.union(recursive, {:all=>opts[:union_all] != false, :from_self=>false}))])
971
+ clone(:with=>(@opts[:with]||[]) + [Hash[opts].merge!(:recursive=>true, :name=>name, :dataset=>nonrecursive.union(recursive, {:all=>opts[:union_all] != false, :from_self=>false}))])
972
972
  end
973
973
  end
974
974
 
@@ -1001,7 +1001,7 @@ module Sequel
1001
1001
  s, ds = hoist_cte(dataset)
1002
1002
  return s.compound_clone(type, ds, opts)
1003
1003
  end
1004
- ds = compound_from_self.clone(:compounds=>Array(@opts[:compounds]).map{|x| x.dup} + [[type, dataset.compound_from_self, opts[:all]]])
1004
+ ds = compound_from_self.clone(:compounds=>Array(@opts[:compounds]).map(&:dup) + [[type, dataset.compound_from_self, opts[:all]]])
1005
1005
  opts[:from_self] == false ? ds : ds.from_self(opts)
1006
1006
  end
1007
1007
 
@@ -8,70 +8,73 @@ module Sequel
8
8
  end
9
9
 
10
10
  # Error raised when the adapter requested doesn't exist or can't be loaded.
11
- class AdapterNotFound < Error; end
11
+ AdapterNotFound = Class.new(Error)
12
12
 
13
13
  # Generic error raised by the database adapters, indicating a
14
14
  # problem originating from the database server. Usually raised
15
15
  # because incorrect SQL syntax is used.
16
- class DatabaseError < Error; end
16
+ DatabaseError = Class.new(Error)
17
17
 
18
18
  # Error raised when the Sequel is unable to connect to the database with the
19
19
  # connection parameters it was given.
20
- class DatabaseConnectionError < DatabaseError; end
20
+ DatabaseConnectionError = Class.new(DatabaseError)
21
21
 
22
22
  # Error raised by adapters when they determine that the connection
23
23
  # to the database has been lost. Instructs the connection pool code to
24
24
  # remove that connection from the pool so that other connections can be acquired
25
25
  # automatically.
26
- class DatabaseDisconnectError < DatabaseError; end
26
+ DatabaseDisconnectError = Class.new(DatabaseError)
27
27
 
28
28
  # Generic error raised when Sequel determines a database constraint has been violated.
29
- class ConstraintViolation < DatabaseError; end
29
+ ConstraintViolation = Class.new(DatabaseError)
30
30
 
31
31
  # Error raised when Sequel determines a database check constraint has been violated.
32
- class CheckConstraintViolation < ConstraintViolation; end
32
+ CheckConstraintViolation = Class.new(ConstraintViolation)
33
33
 
34
34
  # Error raised when Sequel determines a database foreign key constraint has been violated.
35
- class ForeignKeyConstraintViolation < ConstraintViolation; end
35
+ ForeignKeyConstraintViolation = Class.new(ConstraintViolation)
36
36
 
37
37
  # Error raised when Sequel determines a database NOT NULL constraint has been violated.
38
- class NotNullConstraintViolation < ConstraintViolation; end
38
+ NotNullConstraintViolation = Class.new(ConstraintViolation)
39
39
 
40
40
  # Error raised when Sequel determines a database unique constraint has been violated.
41
- class UniqueConstraintViolation < ConstraintViolation; end
41
+ UniqueConstraintViolation = Class.new(ConstraintViolation)
42
42
 
43
43
  # Error raised when Sequel determines a serialization failure/deadlock in the database.
44
- class SerializationFailure < DatabaseError; end
44
+ SerializationFailure = Class.new(DatabaseError)
45
45
 
46
46
  # Error raised on an invalid operation, such as trying to update or delete
47
47
  # a joined or grouped dataset.
48
- class InvalidOperation < Error; end
48
+ InvalidOperation = Class.new(Error)
49
49
 
50
50
  # Error raised when attempting an invalid type conversion.
51
- class InvalidValue < Error; end
51
+ InvalidValue = Class.new(Error)
52
52
 
53
53
  # Error raised when the user requests a record via the first! or similar
54
54
  # method, and the dataset does not yield any rows.
55
- class NoMatchingRow < Error; end
55
+ NoMatchingRow = Class.new(Error)
56
56
 
57
57
  # Error raised when the connection pool cannot acquire a database connection
58
58
  # before the timeout.
59
- class PoolTimeout < Error; end
59
+ PoolTimeout = Class.new(Error)
60
60
 
61
61
  # Error that you should raise to signal a rollback of the current transaction.
62
62
  # The transaction block will catch this exception, rollback the current transaction,
63
63
  # and won't reraise it (unless a reraise is requested).
64
- class Rollback < Error; end
64
+ Rollback = Class.new(Error)
65
65
 
66
66
  # Error raised when unbinding a dataset that has multiple different values
67
67
  # for a given variable.
68
- class UnbindDuplicate < Error; end
69
-
70
- class Error
71
- AdapterNotFound = Sequel::AdapterNotFound
72
- InvalidOperation = Sequel::InvalidOperation
73
- InvalidValue = Sequel::InvalidValue
74
- PoolTimeoutError = Sequel::PoolTimeout
75
- Rollback = Sequel::Rollback
76
- end
68
+ UnbindDuplicate = Class.new(Error)
69
+
70
+ # Call name on each class to set the name for the class, so it gets cached.
71
+ constants.map{|c| const_get(c)}.each do |c|
72
+ Class === c && c.name
73
+ end
74
+
75
+ Error::AdapterNotFound = AdapterNotFound
76
+ Error::InvalidOperation = InvalidOperation
77
+ Error::InvalidValue = InvalidValue
78
+ Error::PoolTimeoutError = PoolTimeout
79
+ Error::Rollback = Rollback
77
80
  end
@@ -23,7 +23,7 @@ module Sequel
23
23
 
24
24
  # Return the string that #print will print via puts.
25
25
  def self.string(records, columns = nil) # records is an array of hashes
26
- columns ||= records.first.keys.sort_by{|x|x.to_s}
26
+ columns ||= records.first.keys.sort_by(&:to_s)
27
27
  sizes = column_sizes(records, columns)
28
28
  sep_line = separator_line(columns, sizes)
29
29
 
@@ -146,7 +146,7 @@ module Sequel
146
146
  %w'presence unique'.each do |v|
147
147
  class_eval(<<-END, __FILE__, __LINE__+1)
148
148
  def #{v}(columns, opts=OPTS)
149
- @generator.validation({:type=>:#{v}, :columns=>Array(columns)}.merge(opts))
149
+ @generator.validation({:type=>:#{v}, :columns=>Array(columns)}.merge!(opts))
150
150
  end
151
151
  END
152
152
  end
@@ -155,7 +155,7 @@ module Sequel
155
155
  %w'exact_length min_length max_length length_range format like ilike includes'.each do |v|
156
156
  class_eval(<<-END, __FILE__, __LINE__+1)
157
157
  def #{v}(arg, columns, opts=OPTS)
158
- @generator.validation({:type=>:#{v}, :columns=>Array(columns), :arg=>arg}.merge(opts))
158
+ @generator.validation({:type=>:#{v}, :columns=>Array(columns), :arg=>arg}.merge!(opts))
159
159
  end
160
160
  END
161
161
  end
@@ -60,7 +60,7 @@ module Sequel
60
60
  MSSQL_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| Sequel.lit(s.to_s[0...-1]).freeze}).freeze
61
61
  H2_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| s.to_s[0...-1].freeze}).freeze
62
62
  DERBY_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| Sequel.lit("SQL_TSI_#{s.to_s.upcase[0...-1]}").freeze}).freeze
63
- ACCESS_DURATION_UNITS = DURATION_UNITS.zip(%w'yyyy m d h n s'.map{|s| s.freeze}).freeze
63
+ ACCESS_DURATION_UNITS = DURATION_UNITS.zip(%w'yyyy m d h n s'.map(&:freeze)).freeze
64
64
  DB2_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| Sequel.lit(s.to_s).freeze}).freeze
65
65
  FDBSQL_DURATION_UNITS = DURATION_UNITS.zip(DURATION_UNITS.map{|s| Sequel.lit(s.to_s.chop).freeze}).freeze
66
66
 
@@ -180,7 +180,7 @@ module Sequel
180
180
  else
181
181
  h = Hash.new(0)
182
182
  interval.parts.each{|unit, value| h[unit] += value}
183
- {}.merge(h)
183
+ Hash[h]
184
184
  end
185
185
  end
186
186
 
@@ -227,7 +227,7 @@ module Sequel
227
227
  # affect global state, unlike PGArray.register. See PGArray.register for
228
228
  # possible options.
229
229
  def register_array_type(db_type, opts=OPTS, &block)
230
- opts = {:type_procs=>conversion_procs, :typecast_method_map=>@pg_array_schema_types, :typecast_methods_module=>(class << self; self; end)}.merge(opts)
230
+ opts = {:type_procs=>conversion_procs, :typecast_method_map=>@pg_array_schema_types, :typecast_methods_module=>(class << self; self; end)}.merge!(opts)
231
231
  unless (opts.has_key?(:scalar_oid) || block) && opts.has_key?(:oid)
232
232
  array_oid, scalar_oid = from(:pg_type).where(:typname=>db_type.to_s).get([:typarray, :oid])
233
233
  opts[:scalar_oid] = scalar_oid unless opts.has_key?(:scalar_oid) || block
@@ -300,6 +300,15 @@ module Sequel
300
300
  end
301
301
  end
302
302
 
303
+ # Convert ruby arrays to PostgreSQL arrays when used as default values.
304
+ def column_definition_default_sql(sql, column)
305
+ if (d = column[:default]) && d.is_a?(Array) && !Sequel.condition_specifier?(d)
306
+ sql << " DEFAULT (#{literal(Sequel.pg_array(d))}::#{type_literal(column)})"
307
+ else
308
+ super
309
+ end
310
+ end
311
+
303
312
  # Given a value to typecast and the type of PGArray subclass:
304
313
  # * If given a PGArray with a matching array_type, use it directly.
305
314
  # * If given a PGArray with a different array_type, return a PGArray
@@ -445,7 +445,7 @@ module Sequel
445
445
  end
446
446
  # Manually cast to integer using to_i, because adapter may not cast oid type
447
447
  # correctly (e.g. swift)
448
- parser_opts[:oid], rel_oid, array_oid = row.values_at(:oid, :typrelid, :typarray).map{|i| i.to_i}
448
+ parser_opts[:oid], rel_oid, array_oid = row.values_at(:oid, :typrelid, :typarray).map(&:to_i)
449
449
 
450
450
  # Get column names and oids for each of the members of the composite type.
451
451
  res = from(:pg_attribute).
@@ -123,7 +123,7 @@ SQL
123
123
 
124
124
  Thread.new do
125
125
  begin
126
- listen(opts[:channel_name]||default_static_cache_update_name, {:loop=>true}.merge(opts)) do |_, _, oid|
126
+ listen(opts[:channel_name]||default_static_cache_update_name, {:loop=>true}.merge!(opts)) do |_, _, oid|
127
127
  if model = oid_map[oid.to_i]
128
128
  model.send(:load_cache)
129
129
  end
@@ -73,7 +73,7 @@ module Sequel
73
73
  <<END_MIG
74
74
  Sequel.migration do
75
75
  change do
76
- #{ts.sort_by{|t| t.to_s}.map{|t| dump_table_foreign_keys(t)}.reject{|x| x == ''}.join("\n\n").gsub(/^/o, ' ')}
76
+ #{ts.sort_by(&:to_s).map{|t| dump_table_foreign_keys(t)}.reject{|x| x == ''}.join("\n\n").gsub(/^/o, ' ')}
77
77
  end
78
78
  end
79
79
  END_MIG
@@ -91,7 +91,7 @@ END_MIG
91
91
  <<END_MIG
92
92
  Sequel.migration do
93
93
  change do
94
- #{ts.sort_by{|t| t.to_s}.map{|t| dump_table_indexes(t, :add_index, options)}.reject{|x| x == ''}.join("\n\n").gsub(/^/o, ' ')}
94
+ #{ts.sort_by(&:to_s).map{|t| dump_table_indexes(t, :add_index, options)}.reject{|x| x == ''}.join("\n\n").gsub(/^/o, ' ')}
95
95
  end
96
96
  end
97
97
  END_MIG
@@ -207,7 +207,7 @@ END_MIG
207
207
  def dump_add_fk_constraints(table, fks)
208
208
  sfks = "alter_table(#{table.inspect}) do\n"
209
209
  sfks << create_table_generator do
210
- fks.sort_by{|fk| fk[:columns].map{|c| c.to_s}}.each do |fk|
210
+ fks.sort_by{|fk| fk[:columns].map(&:to_s)}.each do |fk|
211
211
  foreign_key fk[:columns], fk
212
212
  end
213
213
  end.dump_constraints.gsub(/^foreign_key /, ' add_foreign_key ')
@@ -218,7 +218,7 @@ END_MIG
218
218
  # string that would add the foreign keys if run in a migration.
219
219
  def dump_table_foreign_keys(table, options=OPTS)
220
220
  if supports_foreign_key_parsing?
221
- fks = foreign_key_list(table, options).sort_by{|fk| fk[:columns].map{|c| c.to_s}}
221
+ fks = foreign_key_list(table, options).sort_by{|fk| fk[:columns].map(&:to_s)}
222
222
  end
223
223
 
224
224
  if fks.nil? || fks.empty?
@@ -234,7 +234,7 @@ END_MIG
234
234
  table = table.value.to_s if table.is_a?(SQL::Identifier)
235
235
  raise(Error, "must provide table as a Symbol, String, or Sequel::SQL::Identifier") unless [String, Symbol].any?{|c| table.is_a?(c)}
236
236
  s = schema(table).dup
237
- pks = s.find_all{|x| x.last[:primary_key] == true}.map{|x| x.first}
237
+ pks = s.find_all{|x| x.last[:primary_key] == true}.map(&:first)
238
238
  options = options.merge(:single_pk=>true) if pks.length == 1
239
239
  m = method(:recreate_column)
240
240
  im = method(:index_to_generator_opts)
@@ -319,7 +319,7 @@ END_MIG
319
319
  options[:skipped_foreign_keys] = skipped_foreign_keys
320
320
  tables
321
321
  else
322
- tables.sort_by{|t| t.to_s}
322
+ tables.sort_by(&:to_s)
323
323
  end
324
324
  end
325
325
 
@@ -351,7 +351,7 @@ END_MIG
351
351
  end
352
352
 
353
353
  # Add sorted tables from this loop to the final list
354
- sorted_tables.concat(this_loop.sort_by{|t| t.to_s})
354
+ sorted_tables.concat(this_loop.sort_by(&:to_s))
355
355
 
356
356
  # Remove tables that were handled this loop
357
357
  this_loop.each{|t| table_fks.delete(t)}
@@ -417,7 +417,7 @@ END_MIG
417
417
  if !name and c[:check].length == 1 and c[:check].first.is_a?(Hash)
418
418
  "check #{c[:check].first.inspect[1...-1]}"
419
419
  else
420
- "#{name ? "constraint #{name.inspect}," : 'check'} #{c[:check].map{|x| x.inspect}.join(', ')}"
420
+ "#{name ? "constraint #{name.inspect}," : 'check'} #{c[:check].map(&:inspect).join(', ')}"
421
421
  end
422
422
  when :foreign_key
423
423
  c.delete(:on_delete) if c[:on_delete] == :no_action