activerecord 3.2.22.5 → 4.2.11.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (236) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1632 -609
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +37 -41
  5. data/examples/performance.rb +31 -19
  6. data/examples/simple.rb +4 -4
  7. data/lib/active_record/aggregations.rb +56 -42
  8. data/lib/active_record/association_relation.rb +35 -0
  9. data/lib/active_record/associations/alias_tracker.rb +47 -36
  10. data/lib/active_record/associations/association.rb +73 -55
  11. data/lib/active_record/associations/association_scope.rb +143 -82
  12. data/lib/active_record/associations/belongs_to_association.rb +65 -25
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
  14. data/lib/active_record/associations/builder/association.rb +125 -31
  15. data/lib/active_record/associations/builder/belongs_to.rb +89 -61
  16. data/lib/active_record/associations/builder/collection_association.rb +69 -49
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +113 -42
  18. data/lib/active_record/associations/builder/has_many.rb +8 -64
  19. data/lib/active_record/associations/builder/has_one.rb +12 -51
  20. data/lib/active_record/associations/builder/singular_association.rb +23 -17
  21. data/lib/active_record/associations/collection_association.rb +251 -177
  22. data/lib/active_record/associations/collection_proxy.rb +963 -63
  23. data/lib/active_record/associations/foreign_association.rb +11 -0
  24. data/lib/active_record/associations/has_many_association.rb +113 -22
  25. data/lib/active_record/associations/has_many_through_association.rb +99 -39
  26. data/lib/active_record/associations/has_one_association.rb +43 -20
  27. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  28. data/lib/active_record/associations/join_dependency/join_association.rb +76 -107
  29. data/lib/active_record/associations/join_dependency/join_base.rb +7 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +30 -37
  31. data/lib/active_record/associations/join_dependency.rb +230 -156
  32. data/lib/active_record/associations/preloader/association.rb +96 -55
  33. data/lib/active_record/associations/preloader/collection_association.rb +3 -3
  34. data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
  35. data/lib/active_record/associations/preloader/has_one.rb +1 -1
  36. data/lib/active_record/associations/preloader/singular_association.rb +3 -3
  37. data/lib/active_record/associations/preloader/through_association.rb +62 -33
  38. data/lib/active_record/associations/preloader.rb +101 -79
  39. data/lib/active_record/associations/singular_association.rb +29 -13
  40. data/lib/active_record/associations/through_association.rb +30 -16
  41. data/lib/active_record/associations.rb +463 -345
  42. data/lib/active_record/attribute.rb +163 -0
  43. data/lib/active_record/attribute_assignment.rb +142 -151
  44. data/lib/active_record/attribute_decorators.rb +66 -0
  45. data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
  46. data/lib/active_record/attribute_methods/dirty.rb +137 -57
  47. data/lib/active_record/attribute_methods/primary_key.rb +50 -36
  48. data/lib/active_record/attribute_methods/query.rb +5 -4
  49. data/lib/active_record/attribute_methods/read.rb +73 -106
  50. data/lib/active_record/attribute_methods/serialization.rb +44 -94
  51. data/lib/active_record/attribute_methods/time_zone_conversion.rb +49 -45
  52. data/lib/active_record/attribute_methods/write.rb +57 -44
  53. data/lib/active_record/attribute_methods.rb +301 -141
  54. data/lib/active_record/attribute_set/builder.rb +106 -0
  55. data/lib/active_record/attribute_set.rb +81 -0
  56. data/lib/active_record/attributes.rb +147 -0
  57. data/lib/active_record/autosave_association.rb +246 -217
  58. data/lib/active_record/base.rb +70 -474
  59. data/lib/active_record/callbacks.rb +66 -28
  60. data/lib/active_record/coders/json.rb +13 -0
  61. data/lib/active_record/coders/yaml_column.rb +18 -21
  62. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +396 -219
  63. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  64. data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -164
  65. data/lib/active_record/connection_adapters/abstract/query_cache.rb +29 -24
  66. data/lib/active_record/connection_adapters/abstract/quoting.rb +74 -55
  67. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  68. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +125 -0
  69. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +261 -169
  70. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +50 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +707 -259
  72. data/lib/active_record/connection_adapters/abstract/transaction.rb +215 -0
  73. data/lib/active_record/connection_adapters/abstract_adapter.rb +298 -89
  74. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +466 -196
  75. data/lib/active_record/connection_adapters/column.rb +31 -245
  76. data/lib/active_record/connection_adapters/connection_specification.rb +275 -0
  77. data/lib/active_record/connection_adapters/mysql2_adapter.rb +45 -57
  78. data/lib/active_record/connection_adapters/mysql_adapter.rb +180 -123
  79. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +93 -0
  80. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  81. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +232 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +36 -0
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +108 -0
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +596 -0
  112. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  113. data/lib/active_record/connection_adapters/postgresql_adapter.rb +430 -999
  114. data/lib/active_record/connection_adapters/schema_cache.rb +52 -27
  115. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +579 -22
  116. data/lib/active_record/connection_handling.rb +132 -0
  117. data/lib/active_record/core.rb +579 -0
  118. data/lib/active_record/counter_cache.rb +157 -105
  119. data/lib/active_record/dynamic_matchers.rb +119 -63
  120. data/lib/active_record/enum.rb +197 -0
  121. data/lib/active_record/errors.rb +94 -36
  122. data/lib/active_record/explain.rb +15 -63
  123. data/lib/active_record/explain_registry.rb +30 -0
  124. data/lib/active_record/explain_subscriber.rb +9 -5
  125. data/lib/active_record/fixture_set/file.rb +56 -0
  126. data/lib/active_record/fixtures.rb +302 -215
  127. data/lib/active_record/gem_version.rb +15 -0
  128. data/lib/active_record/inheritance.rb +143 -70
  129. data/lib/active_record/integration.rb +65 -12
  130. data/lib/active_record/legacy_yaml_adapter.rb +30 -0
  131. data/lib/active_record/locale/en.yml +8 -1
  132. data/lib/active_record/locking/optimistic.rb +73 -52
  133. data/lib/active_record/locking/pessimistic.rb +5 -5
  134. data/lib/active_record/log_subscriber.rb +24 -21
  135. data/lib/active_record/migration/command_recorder.rb +124 -32
  136. data/lib/active_record/migration/join_table.rb +15 -0
  137. data/lib/active_record/migration.rb +511 -213
  138. data/lib/active_record/model_schema.rb +91 -117
  139. data/lib/active_record/nested_attributes.rb +184 -130
  140. data/lib/active_record/no_touching.rb +52 -0
  141. data/lib/active_record/null_relation.rb +81 -0
  142. data/lib/active_record/persistence.rb +276 -117
  143. data/lib/active_record/query_cache.rb +19 -37
  144. data/lib/active_record/querying.rb +28 -18
  145. data/lib/active_record/railtie.rb +73 -40
  146. data/lib/active_record/railties/console_sandbox.rb +3 -4
  147. data/lib/active_record/railties/controller_runtime.rb +4 -3
  148. data/lib/active_record/railties/databases.rake +141 -416
  149. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  150. data/lib/active_record/readonly_attributes.rb +1 -4
  151. data/lib/active_record/reflection.rb +513 -154
  152. data/lib/active_record/relation/batches.rb +91 -43
  153. data/lib/active_record/relation/calculations.rb +199 -161
  154. data/lib/active_record/relation/delegation.rb +116 -25
  155. data/lib/active_record/relation/finder_methods.rb +362 -248
  156. data/lib/active_record/relation/merger.rb +193 -0
  157. data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
  158. data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
  159. data/lib/active_record/relation/predicate_builder.rb +135 -43
  160. data/lib/active_record/relation/query_methods.rb +928 -167
  161. data/lib/active_record/relation/spawn_methods.rb +48 -149
  162. data/lib/active_record/relation.rb +352 -207
  163. data/lib/active_record/result.rb +101 -10
  164. data/lib/active_record/runtime_registry.rb +22 -0
  165. data/lib/active_record/sanitization.rb +56 -59
  166. data/lib/active_record/schema.rb +19 -13
  167. data/lib/active_record/schema_dumper.rb +106 -63
  168. data/lib/active_record/schema_migration.rb +53 -0
  169. data/lib/active_record/scoping/default.rb +50 -57
  170. data/lib/active_record/scoping/named.rb +73 -109
  171. data/lib/active_record/scoping.rb +58 -123
  172. data/lib/active_record/serialization.rb +6 -2
  173. data/lib/active_record/serializers/xml_serializer.rb +12 -22
  174. data/lib/active_record/statement_cache.rb +111 -0
  175. data/lib/active_record/store.rb +168 -15
  176. data/lib/active_record/tasks/database_tasks.rb +299 -0
  177. data/lib/active_record/tasks/mysql_database_tasks.rb +159 -0
  178. data/lib/active_record/tasks/postgresql_database_tasks.rb +101 -0
  179. data/lib/active_record/tasks/sqlite_database_tasks.rb +55 -0
  180. data/lib/active_record/timestamp.rb +23 -16
  181. data/lib/active_record/transactions.rb +125 -79
  182. data/lib/active_record/type/big_integer.rb +13 -0
  183. data/lib/active_record/type/binary.rb +50 -0
  184. data/lib/active_record/type/boolean.rb +31 -0
  185. data/lib/active_record/type/date.rb +50 -0
  186. data/lib/active_record/type/date_time.rb +54 -0
  187. data/lib/active_record/type/decimal.rb +64 -0
  188. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  189. data/lib/active_record/type/decorator.rb +14 -0
  190. data/lib/active_record/type/float.rb +19 -0
  191. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  192. data/lib/active_record/type/integer.rb +59 -0
  193. data/lib/active_record/type/mutable.rb +16 -0
  194. data/lib/active_record/type/numeric.rb +36 -0
  195. data/lib/active_record/type/serialized.rb +62 -0
  196. data/lib/active_record/type/string.rb +40 -0
  197. data/lib/active_record/type/text.rb +11 -0
  198. data/lib/active_record/type/time.rb +26 -0
  199. data/lib/active_record/type/time_value.rb +38 -0
  200. data/lib/active_record/type/type_map.rb +64 -0
  201. data/lib/active_record/type/unsigned_integer.rb +15 -0
  202. data/lib/active_record/type/value.rb +110 -0
  203. data/lib/active_record/type.rb +23 -0
  204. data/lib/active_record/validations/associated.rb +24 -16
  205. data/lib/active_record/validations/presence.rb +67 -0
  206. data/lib/active_record/validations/uniqueness.rb +123 -64
  207. data/lib/active_record/validations.rb +36 -29
  208. data/lib/active_record/version.rb +5 -7
  209. data/lib/active_record.rb +66 -46
  210. data/lib/rails/generators/active_record/migration/migration_generator.rb +53 -8
  211. data/lib/rails/generators/active_record/{model/templates/migration.rb → migration/templates/create_table_migration.rb} +5 -1
  212. data/lib/rails/generators/active_record/migration/templates/migration.rb +20 -15
  213. data/lib/rails/generators/active_record/migration.rb +11 -8
  214. data/lib/rails/generators/active_record/model/model_generator.rb +9 -4
  215. data/lib/rails/generators/active_record/model/templates/model.rb +4 -6
  216. data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
  217. data/lib/rails/generators/active_record.rb +3 -11
  218. metadata +101 -45
  219. data/examples/associations.png +0 -0
  220. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
  221. data/lib/active_record/associations/join_helper.rb +0 -55
  222. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  223. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  224. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
  225. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
  226. data/lib/active_record/dynamic_finder_match.rb +0 -68
  227. data/lib/active_record/dynamic_scope_match.rb +0 -23
  228. data/lib/active_record/fixtures/file.rb +0 -65
  229. data/lib/active_record/identity_map.rb +0 -162
  230. data/lib/active_record/observer.rb +0 -121
  231. data/lib/active_record/session_store.rb +0 -360
  232. data/lib/active_record/test_case.rb +0 -73
  233. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  234. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  235. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  236. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -1,4 +1,5 @@
1
1
  require 'active_support/core_ext/big_decimal/conversions'
2
+ require "active_support/multibyte/chars"
2
3
 
3
4
  module ActiveRecord
4
5
  module ConnectionAdapters # :nodoc:
@@ -9,70 +10,29 @@ module ActiveRecord
9
10
  # records are quoted as their primary key
10
11
  return value.quoted_id if value.respond_to?(:quoted_id)
11
12
 
12
- case value
13
- when String, ActiveSupport::Multibyte::Chars
14
- value = value.to_s
15
- return "'#{quote_string(value)}'" unless column
16
-
17
- case column.type
18
- when :binary then "'#{quote_string(column.string_to_binary(value))}'"
19
- when :integer then value.to_i.to_s
20
- when :float then value.to_f.to_s
21
- else
22
- "'#{quote_string(value)}'"
23
- end
24
-
25
- when true, false
26
- if column && column.type == :integer
27
- value ? '1' : '0'
28
- else
29
- value ? quoted_true : quoted_false
30
- end
31
- # BigDecimals need to be put in a non-normalized form and quoted.
32
- when nil then "NULL"
33
- when BigDecimal then value.to_s('F')
34
- when Numeric then value.to_s
35
- when Date, Time then "'#{quoted_date(value)}'"
36
- when Symbol then "'#{quote_string(value.to_s)}'"
37
- else
38
- "'#{quote_string(YAML.dump(value))}'"
13
+ if column
14
+ value = column.cast_type.type_cast_for_database(value)
39
15
  end
16
+
17
+ _quote(value)
40
18
  end
41
19
 
42
20
  # Cast a +value+ to a type that the database understands. For example,
43
21
  # SQLite does not understand dates, so this method will convert a Date
44
22
  # to a String.
45
23
  def type_cast(value, column)
46
- return value.id if value.respond_to?(:quoted_id)
47
-
48
- case value
49
- when String, ActiveSupport::Multibyte::Chars
50
- value = value.to_s
51
- return value unless column
52
-
53
- case column.type
54
- when :binary then value
55
- when :integer then value.to_i
56
- when :float then value.to_f
57
- else
58
- value
59
- end
24
+ if value.respond_to?(:quoted_id) && value.respond_to?(:id)
25
+ return value.id
26
+ end
60
27
 
61
- when true, false
62
- if column && column.type == :integer
63
- value ? 1 : 0
64
- else
65
- value ? 't' : 'f'
66
- end
67
- # BigDecimals need to be put in a non-normalized form and quoted.
68
- when nil then nil
69
- when BigDecimal then value.to_s('F')
70
- when Numeric then value
71
- when Date, Time then quoted_date(value)
72
- when Symbol then value.to_s
73
- else
74
- YAML.dump(value)
28
+ if column
29
+ value = column.cast_type.type_cast_for_database(value)
75
30
  end
31
+
32
+ _type_cast(value)
33
+ rescue TypeError
34
+ to_type = column ? " to #{column.type}" : ""
35
+ raise TypeError, "can't cast #{value.class}#{to_type}"
76
36
  end
77
37
 
78
38
  # Quotes a string, escaping any ' (single quote) and \ (backslash)
@@ -91,14 +51,34 @@ module ActiveRecord
91
51
  quote_column_name(table_name)
92
52
  end
93
53
 
54
+ # Override to return the quoted table name for assignment. Defaults to
55
+ # table quoting.
56
+ #
57
+ # This works for mysql and mysql2 where table.column can be used to
58
+ # resolve ambiguity.
59
+ #
60
+ # We override this in the sqlite3 and postgresql adapters to use only
61
+ # the column name (as per syntax requirements).
62
+ def quote_table_name_for_assignment(table, attr)
63
+ quote_table_name("#{table}.#{attr}")
64
+ end
65
+
94
66
  def quoted_true
95
67
  "'t'"
96
68
  end
97
69
 
70
+ def unquoted_true
71
+ 't'
72
+ end
73
+
98
74
  def quoted_false
99
75
  "'f'"
100
76
  end
101
77
 
78
+ def unquoted_false
79
+ 'f'
80
+ end
81
+
102
82
  def quoted_date(value)
103
83
  if value.acts_like?(:time)
104
84
  zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
@@ -110,6 +90,45 @@ module ActiveRecord
110
90
 
111
91
  value.to_s(:db)
112
92
  end
93
+
94
+ private
95
+
96
+ def types_which_need_no_typecasting
97
+ [nil, Numeric, String]
98
+ end
99
+
100
+ def _quote(value)
101
+ case value
102
+ when String, ActiveSupport::Multibyte::Chars, Type::Binary::Data
103
+ "'#{quote_string(value.to_s)}'"
104
+ when true then quoted_true
105
+ when false then quoted_false
106
+ when nil then "NULL"
107
+ # BigDecimals need to be put in a non-normalized form and quoted.
108
+ when BigDecimal then value.to_s('F')
109
+ when Numeric, ActiveSupport::Duration then value.to_s
110
+ when Date, Time then "'#{quoted_date(value)}'"
111
+ when Symbol then "'#{quote_string(value.to_s)}'"
112
+ when Class then "'#{value}'"
113
+ else
114
+ "'#{quote_string(YAML.dump(value))}'"
115
+ end
116
+ end
117
+
118
+ def _type_cast(value)
119
+ case value
120
+ when Symbol, ActiveSupport::Multibyte::Chars, Type::Binary::Data
121
+ value.to_s
122
+ when true then unquoted_true
123
+ when false then unquoted_false
124
+ # BigDecimals need to be put in a non-normalized form and quoted.
125
+ when BigDecimal then value.to_s('F')
126
+ when Date, Time then quoted_date(value)
127
+ when *types_which_need_no_typecasting
128
+ value
129
+ else raise TypeError
130
+ end
131
+ end
113
132
  end
114
133
  end
115
134
  end
@@ -0,0 +1,21 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module Savepoints #:nodoc:
4
+ def supports_savepoints?
5
+ true
6
+ end
7
+
8
+ def create_savepoint(name = current_savepoint_name)
9
+ execute("SAVEPOINT #{name}")
10
+ end
11
+
12
+ def exec_rollback_to_savepoint(name = current_savepoint_name)
13
+ execute("ROLLBACK TO SAVEPOINT #{name}")
14
+ end
15
+
16
+ def release_savepoint(name = current_savepoint_name)
17
+ execute("RELEASE SAVEPOINT #{name}")
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,125 @@
1
+ require 'active_support/core_ext/string/strip'
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ class AbstractAdapter
6
+ class SchemaCreation # :nodoc:
7
+ def initialize(conn)
8
+ @conn = conn
9
+ @cache = {}
10
+ end
11
+
12
+ def accept(o)
13
+ m = @cache[o.class] ||= "visit_#{o.class.name.split('::').last}"
14
+ send m, o
15
+ end
16
+
17
+ def visit_AddColumn(o)
18
+ "ADD #{accept(o)}"
19
+ end
20
+
21
+ private
22
+
23
+ def visit_AlterTable(o)
24
+ sql = "ALTER TABLE #{quote_table_name(o.name)} "
25
+ sql << o.adds.map { |col| visit_AddColumn col }.join(' ')
26
+ sql << o.foreign_key_adds.map { |fk| visit_AddForeignKey fk }.join(' ')
27
+ sql << o.foreign_key_drops.map { |fk| visit_DropForeignKey fk }.join(' ')
28
+ end
29
+
30
+ def visit_ColumnDefinition(o)
31
+ sql_type = type_to_sql(o.type, o.limit, o.precision, o.scale)
32
+ column_sql = "#{quote_column_name(o.name)} #{sql_type}"
33
+ add_column_options!(column_sql, column_options(o)) unless o.primary_key?
34
+ column_sql
35
+ end
36
+
37
+ def visit_TableDefinition(o)
38
+ create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE "
39
+ create_sql << "#{quote_table_name(o.name)} "
40
+ create_sql << "(#{o.columns.map { |c| accept c }.join(', ')}) " unless o.as
41
+ create_sql << "#{o.options}"
42
+ create_sql << " AS #{@conn.to_sql(o.as)}" if o.as
43
+ create_sql
44
+ end
45
+
46
+ def visit_AddForeignKey(o)
47
+ sql = <<-SQL.strip_heredoc
48
+ ADD CONSTRAINT #{quote_column_name(o.name)}
49
+ FOREIGN KEY (#{quote_column_name(o.column)})
50
+ REFERENCES #{quote_table_name(o.to_table)} (#{quote_column_name(o.primary_key)})
51
+ SQL
52
+ sql << " #{action_sql('DELETE', o.on_delete)}" if o.on_delete
53
+ sql << " #{action_sql('UPDATE', o.on_update)}" if o.on_update
54
+ sql
55
+ end
56
+
57
+ def visit_DropForeignKey(name)
58
+ "DROP CONSTRAINT #{quote_column_name(name)}"
59
+ end
60
+
61
+ def column_options(o)
62
+ column_options = {}
63
+ column_options[:null] = o.null unless o.null.nil?
64
+ column_options[:default] = o.default unless o.default.nil?
65
+ column_options[:column] = o
66
+ column_options[:first] = o.first
67
+ column_options[:after] = o.after
68
+ column_options
69
+ end
70
+
71
+ def quote_column_name(name)
72
+ @conn.quote_column_name name
73
+ end
74
+
75
+ def quote_table_name(name)
76
+ @conn.quote_table_name name
77
+ end
78
+
79
+ def type_to_sql(type, limit, precision, scale)
80
+ @conn.type_to_sql type.to_sym, limit, precision, scale
81
+ end
82
+
83
+ def add_column_options!(sql, options)
84
+ sql << " DEFAULT #{quote_value(options[:default], options[:column])}" if options_include_default?(options)
85
+ # must explicitly check for :null to allow change_column to work on migrations
86
+ if options[:null] == false
87
+ sql << " NOT NULL"
88
+ end
89
+ if options[:auto_increment] == true
90
+ sql << " AUTO_INCREMENT"
91
+ end
92
+ sql
93
+ end
94
+
95
+ def quote_value(value, column)
96
+ column.sql_type ||= type_to_sql(column.type, column.limit, column.precision, column.scale)
97
+ column.cast_type ||= type_for_column(column)
98
+
99
+ @conn.quote(value, column)
100
+ end
101
+
102
+ def options_include_default?(options)
103
+ options.include?(:default) && !(options[:null] == false && options[:default].nil?)
104
+ end
105
+
106
+ def action_sql(action, dependency)
107
+ case dependency
108
+ when :nullify then "ON #{action} SET NULL"
109
+ when :cascade then "ON #{action} CASCADE"
110
+ when :restrict then "ON #{action} RESTRICT"
111
+ else
112
+ raise ArgumentError, <<-MSG.strip_heredoc
113
+ '#{dependency}' is not supported for :on_update or :on_delete.
114
+ Supported values are: :nullify, :cascade, :restrict
115
+ MSG
116
+ end
117
+ end
118
+
119
+ def type_for_column(column)
120
+ @conn.lookup_cast_type(column.sql_type)
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end