sequel 4.21.0 → 4.22.0

Sign up to get free protection for your applications and to get access to all the features.
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