activerecord 1.0.0 → 4.0.0

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 (255) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +2102 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +213 -0
  5. data/examples/performance.rb +172 -0
  6. data/examples/simple.rb +14 -0
  7. data/lib/active_record/aggregations.rb +180 -84
  8. data/lib/active_record/associations/alias_tracker.rb +76 -0
  9. data/lib/active_record/associations/association.rb +248 -0
  10. data/lib/active_record/associations/association_scope.rb +135 -0
  11. data/lib/active_record/associations/belongs_to_association.rb +92 -0
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +35 -0
  13. data/lib/active_record/associations/builder/association.rb +108 -0
  14. data/lib/active_record/associations/builder/belongs_to.rb +98 -0
  15. data/lib/active_record/associations/builder/collection_association.rb +89 -0
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +39 -0
  17. data/lib/active_record/associations/builder/has_many.rb +15 -0
  18. data/lib/active_record/associations/builder/has_one.rb +25 -0
  19. data/lib/active_record/associations/builder/singular_association.rb +32 -0
  20. data/lib/active_record/associations/collection_association.rb +608 -0
  21. data/lib/active_record/associations/collection_proxy.rb +986 -0
  22. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +58 -39
  23. data/lib/active_record/associations/has_many_association.rb +116 -85
  24. data/lib/active_record/associations/has_many_through_association.rb +197 -0
  25. data/lib/active_record/associations/has_one_association.rb +102 -0
  26. data/lib/active_record/associations/has_one_through_association.rb +36 -0
  27. data/lib/active_record/associations/join_dependency/join_association.rb +174 -0
  28. data/lib/active_record/associations/join_dependency/join_base.rb +24 -0
  29. data/lib/active_record/associations/join_dependency/join_part.rb +78 -0
  30. data/lib/active_record/associations/join_dependency.rb +235 -0
  31. data/lib/active_record/associations/join_helper.rb +45 -0
  32. data/lib/active_record/associations/preloader/association.rb +121 -0
  33. data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
  34. data/lib/active_record/associations/preloader/collection_association.rb +24 -0
  35. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +60 -0
  36. data/lib/active_record/associations/preloader/has_many.rb +17 -0
  37. data/lib/active_record/associations/preloader/has_many_through.rb +19 -0
  38. data/lib/active_record/associations/preloader/has_one.rb +23 -0
  39. data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
  40. data/lib/active_record/associations/preloader/singular_association.rb +21 -0
  41. data/lib/active_record/associations/preloader/through_association.rb +63 -0
  42. data/lib/active_record/associations/preloader.rb +178 -0
  43. data/lib/active_record/associations/singular_association.rb +64 -0
  44. data/lib/active_record/associations/through_association.rb +87 -0
  45. data/lib/active_record/associations.rb +1437 -431
  46. data/lib/active_record/attribute_assignment.rb +201 -0
  47. data/lib/active_record/attribute_methods/before_type_cast.rb +70 -0
  48. data/lib/active_record/attribute_methods/dirty.rb +118 -0
  49. data/lib/active_record/attribute_methods/primary_key.rb +122 -0
  50. data/lib/active_record/attribute_methods/query.rb +40 -0
  51. data/lib/active_record/attribute_methods/read.rb +107 -0
  52. data/lib/active_record/attribute_methods/serialization.rb +162 -0
  53. data/lib/active_record/attribute_methods/time_zone_conversion.rb +59 -0
  54. data/lib/active_record/attribute_methods/write.rb +63 -0
  55. data/lib/active_record/attribute_methods.rb +393 -0
  56. data/lib/active_record/autosave_association.rb +426 -0
  57. data/lib/active_record/base.rb +268 -930
  58. data/lib/active_record/callbacks.rb +203 -230
  59. data/lib/active_record/coders/yaml_column.rb +38 -0
  60. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +638 -0
  61. data/lib/active_record/connection_adapters/abstract/database_limits.rb +67 -0
  62. data/lib/active_record/connection_adapters/abstract/database_statements.rb +390 -0
  63. data/lib/active_record/connection_adapters/abstract/query_cache.rb +95 -0
  64. data/lib/active_record/connection_adapters/abstract/quoting.rb +129 -0
  65. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +501 -0
  66. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +70 -0
  67. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +873 -0
  68. data/lib/active_record/connection_adapters/abstract/transaction.rb +203 -0
  69. data/lib/active_record/connection_adapters/abstract_adapter.rb +389 -275
  70. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +782 -0
  71. data/lib/active_record/connection_adapters/column.rb +318 -0
  72. data/lib/active_record/connection_adapters/connection_specification.rb +96 -0
  73. data/lib/active_record/connection_adapters/mysql2_adapter.rb +273 -0
  74. data/lib/active_record/connection_adapters/mysql_adapter.rb +517 -90
  75. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +97 -0
  76. data/lib/active_record/connection_adapters/postgresql/cast.rb +152 -0
  77. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +242 -0
  78. data/lib/active_record/connection_adapters/postgresql/oid.rb +366 -0
  79. data/lib/active_record/connection_adapters/postgresql/quoting.rb +171 -0
  80. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
  81. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +489 -0
  82. data/lib/active_record/connection_adapters/postgresql_adapter.rb +911 -138
  83. data/lib/active_record/connection_adapters/schema_cache.rb +129 -0
  84. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +624 -0
  85. data/lib/active_record/connection_adapters/statement_pool.rb +40 -0
  86. data/lib/active_record/connection_handling.rb +98 -0
  87. data/lib/active_record/core.rb +463 -0
  88. data/lib/active_record/counter_cache.rb +122 -0
  89. data/lib/active_record/dynamic_matchers.rb +131 -0
  90. data/lib/active_record/errors.rb +213 -0
  91. data/lib/active_record/explain.rb +38 -0
  92. data/lib/active_record/explain_registry.rb +30 -0
  93. data/lib/active_record/explain_subscriber.rb +29 -0
  94. data/lib/active_record/fixture_set/file.rb +55 -0
  95. data/lib/active_record/fixtures.rb +892 -138
  96. data/lib/active_record/inheritance.rb +200 -0
  97. data/lib/active_record/integration.rb +60 -0
  98. data/lib/active_record/locale/en.yml +47 -0
  99. data/lib/active_record/locking/optimistic.rb +181 -0
  100. data/lib/active_record/locking/pessimistic.rb +77 -0
  101. data/lib/active_record/log_subscriber.rb +82 -0
  102. data/lib/active_record/migration/command_recorder.rb +164 -0
  103. data/lib/active_record/migration/join_table.rb +15 -0
  104. data/lib/active_record/migration.rb +1015 -0
  105. data/lib/active_record/model_schema.rb +345 -0
  106. data/lib/active_record/nested_attributes.rb +546 -0
  107. data/lib/active_record/null_relation.rb +65 -0
  108. data/lib/active_record/persistence.rb +509 -0
  109. data/lib/active_record/query_cache.rb +56 -0
  110. data/lib/active_record/querying.rb +62 -0
  111. data/lib/active_record/railtie.rb +205 -0
  112. data/lib/active_record/railties/console_sandbox.rb +5 -0
  113. data/lib/active_record/railties/controller_runtime.rb +50 -0
  114. data/lib/active_record/railties/databases.rake +402 -0
  115. data/lib/active_record/railties/jdbcmysql_error.rb +16 -0
  116. data/lib/active_record/readonly_attributes.rb +30 -0
  117. data/lib/active_record/reflection.rb +544 -87
  118. data/lib/active_record/relation/batches.rb +93 -0
  119. data/lib/active_record/relation/calculations.rb +399 -0
  120. data/lib/active_record/relation/delegation.rb +125 -0
  121. data/lib/active_record/relation/finder_methods.rb +349 -0
  122. data/lib/active_record/relation/merger.rb +161 -0
  123. data/lib/active_record/relation/predicate_builder.rb +106 -0
  124. data/lib/active_record/relation/query_methods.rb +1044 -0
  125. data/lib/active_record/relation/spawn_methods.rb +73 -0
  126. data/lib/active_record/relation.rb +655 -0
  127. data/lib/active_record/result.rb +67 -0
  128. data/lib/active_record/runtime_registry.rb +17 -0
  129. data/lib/active_record/sanitization.rb +168 -0
  130. data/lib/active_record/schema.rb +65 -0
  131. data/lib/active_record/schema_dumper.rb +204 -0
  132. data/lib/active_record/schema_migration.rb +39 -0
  133. data/lib/active_record/scoping/default.rb +146 -0
  134. data/lib/active_record/scoping/named.rb +175 -0
  135. data/lib/active_record/scoping.rb +82 -0
  136. data/lib/active_record/serialization.rb +22 -0
  137. data/lib/active_record/serializers/xml_serializer.rb +197 -0
  138. data/lib/active_record/statement_cache.rb +26 -0
  139. data/lib/active_record/store.rb +156 -0
  140. data/lib/active_record/tasks/database_tasks.rb +203 -0
  141. data/lib/active_record/tasks/firebird_database_tasks.rb +56 -0
  142. data/lib/active_record/tasks/mysql_database_tasks.rb +143 -0
  143. data/lib/active_record/tasks/oracle_database_tasks.rb +45 -0
  144. data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
  145. data/lib/active_record/tasks/sqlite_database_tasks.rb +51 -0
  146. data/lib/active_record/tasks/sqlserver_database_tasks.rb +48 -0
  147. data/lib/active_record/test_case.rb +96 -0
  148. data/lib/active_record/timestamp.rb +119 -0
  149. data/lib/active_record/transactions.rb +366 -69
  150. data/lib/active_record/translation.rb +22 -0
  151. data/lib/active_record/validations/associated.rb +49 -0
  152. data/lib/active_record/validations/presence.rb +65 -0
  153. data/lib/active_record/validations/uniqueness.rb +225 -0
  154. data/lib/active_record/validations.rb +64 -185
  155. data/lib/active_record/version.rb +11 -0
  156. data/lib/active_record.rb +149 -24
  157. data/lib/rails/generators/active_record/migration/migration_generator.rb +62 -0
  158. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +19 -0
  159. data/lib/rails/generators/active_record/migration/templates/migration.rb +39 -0
  160. data/lib/rails/generators/active_record/model/model_generator.rb +48 -0
  161. data/lib/rails/generators/active_record/model/templates/model.rb +10 -0
  162. data/lib/rails/generators/active_record/model/templates/module.rb +7 -0
  163. data/lib/rails/generators/active_record.rb +23 -0
  164. metadata +261 -161
  165. data/CHANGELOG +0 -581
  166. data/README +0 -361
  167. data/RUNNING_UNIT_TESTS +0 -36
  168. data/dev-utils/eval_debugger.rb +0 -9
  169. data/examples/associations.png +0 -0
  170. data/examples/associations.rb +0 -87
  171. data/examples/shared_setup.rb +0 -15
  172. data/examples/validation.rb +0 -88
  173. data/install.rb +0 -60
  174. data/lib/active_record/associations/association_collection.rb +0 -70
  175. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -107
  176. data/lib/active_record/deprecated_associations.rb +0 -70
  177. data/lib/active_record/observer.rb +0 -71
  178. data/lib/active_record/support/class_attribute_accessors.rb +0 -43
  179. data/lib/active_record/support/class_inheritable_attributes.rb +0 -37
  180. data/lib/active_record/support/clean_logger.rb +0 -10
  181. data/lib/active_record/support/inflector.rb +0 -70
  182. data/lib/active_record/vendor/mysql.rb +0 -1117
  183. data/lib/active_record/vendor/simple.rb +0 -702
  184. data/lib/active_record/wrappers/yaml_wrapper.rb +0 -15
  185. data/lib/active_record/wrappings.rb +0 -59
  186. data/rakefile +0 -122
  187. data/test/abstract_unit.rb +0 -16
  188. data/test/aggregations_test.rb +0 -34
  189. data/test/all.sh +0 -8
  190. data/test/associations_test.rb +0 -477
  191. data/test/base_test.rb +0 -513
  192. data/test/class_inheritable_attributes_test.rb +0 -33
  193. data/test/connections/native_mysql/connection.rb +0 -24
  194. data/test/connections/native_postgresql/connection.rb +0 -24
  195. data/test/connections/native_sqlite/connection.rb +0 -24
  196. data/test/deprecated_associations_test.rb +0 -336
  197. data/test/finder_test.rb +0 -67
  198. data/test/fixtures/accounts/signals37 +0 -3
  199. data/test/fixtures/accounts/unknown +0 -2
  200. data/test/fixtures/auto_id.rb +0 -4
  201. data/test/fixtures/column_name.rb +0 -3
  202. data/test/fixtures/companies/first_client +0 -6
  203. data/test/fixtures/companies/first_firm +0 -4
  204. data/test/fixtures/companies/second_client +0 -6
  205. data/test/fixtures/company.rb +0 -37
  206. data/test/fixtures/company_in_module.rb +0 -33
  207. data/test/fixtures/course.rb +0 -3
  208. data/test/fixtures/courses/java +0 -2
  209. data/test/fixtures/courses/ruby +0 -2
  210. data/test/fixtures/customer.rb +0 -30
  211. data/test/fixtures/customers/david +0 -6
  212. data/test/fixtures/db_definitions/mysql.sql +0 -96
  213. data/test/fixtures/db_definitions/mysql2.sql +0 -4
  214. data/test/fixtures/db_definitions/postgresql.sql +0 -113
  215. data/test/fixtures/db_definitions/postgresql2.sql +0 -4
  216. data/test/fixtures/db_definitions/sqlite.sql +0 -85
  217. data/test/fixtures/db_definitions/sqlite2.sql +0 -4
  218. data/test/fixtures/default.rb +0 -2
  219. data/test/fixtures/developer.rb +0 -8
  220. data/test/fixtures/developers/david +0 -2
  221. data/test/fixtures/developers/jamis +0 -2
  222. data/test/fixtures/developers_projects/david_action_controller +0 -2
  223. data/test/fixtures/developers_projects/david_active_record +0 -2
  224. data/test/fixtures/developers_projects/jamis_active_record +0 -2
  225. data/test/fixtures/entrant.rb +0 -3
  226. data/test/fixtures/entrants/first +0 -3
  227. data/test/fixtures/entrants/second +0 -3
  228. data/test/fixtures/entrants/third +0 -3
  229. data/test/fixtures/fixture_database.sqlite +0 -0
  230. data/test/fixtures/fixture_database_2.sqlite +0 -0
  231. data/test/fixtures/movie.rb +0 -5
  232. data/test/fixtures/movies/first +0 -2
  233. data/test/fixtures/movies/second +0 -2
  234. data/test/fixtures/project.rb +0 -3
  235. data/test/fixtures/projects/action_controller +0 -2
  236. data/test/fixtures/projects/active_record +0 -2
  237. data/test/fixtures/reply.rb +0 -21
  238. data/test/fixtures/subscriber.rb +0 -5
  239. data/test/fixtures/subscribers/first +0 -2
  240. data/test/fixtures/subscribers/second +0 -2
  241. data/test/fixtures/topic.rb +0 -20
  242. data/test/fixtures/topics/first +0 -9
  243. data/test/fixtures/topics/second +0 -8
  244. data/test/fixtures_test.rb +0 -20
  245. data/test/inflector_test.rb +0 -104
  246. data/test/inheritance_test.rb +0 -125
  247. data/test/lifecycle_test.rb +0 -110
  248. data/test/modules_test.rb +0 -21
  249. data/test/multiple_db_test.rb +0 -46
  250. data/test/pk_test.rb +0 -57
  251. data/test/reflection_test.rb +0 -78
  252. data/test/thread_safety_test.rb +0 -33
  253. data/test/transactions_test.rb +0 -83
  254. data/test/unconnected_test.rb +0 -24
  255. data/test/validations_test.rb +0 -126
@@ -0,0 +1,501 @@
1
+ require 'date'
2
+ require 'set'
3
+ require 'bigdecimal'
4
+ require 'bigdecimal/util'
5
+
6
+ module ActiveRecord
7
+ module ConnectionAdapters #:nodoc:
8
+ # Abstract representation of an index definition on a table. Instances of
9
+ # this type are typically created and returned by methods in database
10
+ # adapters. e.g. ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter#indexes
11
+ class IndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths, :orders, :where, :type, :using) #:nodoc:
12
+ end
13
+
14
+ # Abstract representation of a column definition. Instances of this type
15
+ # are typically created by methods in TableDefinition, and added to the
16
+ # +columns+ attribute of said TableDefinition object, in order to be used
17
+ # for generating a number of table creation or table changing SQL statements.
18
+ class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :primary_key) #:nodoc:
19
+ def string_to_binary(value)
20
+ value
21
+ end
22
+
23
+ def primary_key?
24
+ primary_key || type.to_sym == :primary_key
25
+ end
26
+ end
27
+
28
+ # Represents the schema of an SQL table in an abstract way. This class
29
+ # provides methods for manipulating the schema representation.
30
+ #
31
+ # Inside migration files, the +t+ object in +create_table+
32
+ # is actually of this type:
33
+ #
34
+ # class SomeMigration < ActiveRecord::Migration
35
+ # def up
36
+ # create_table :foo do |t|
37
+ # puts t.class # => "ActiveRecord::ConnectionAdapters::TableDefinition"
38
+ # end
39
+ # end
40
+ #
41
+ # def down
42
+ # ...
43
+ # end
44
+ # end
45
+ #
46
+ # The table definitions
47
+ # The Columns are stored as a ColumnDefinition in the +columns+ attribute.
48
+ class TableDefinition
49
+ # An array of ColumnDefinition objects, representing the column changes
50
+ # that have been defined.
51
+ attr_accessor :indexes
52
+ attr_reader :name, :temporary, :options
53
+
54
+ def initialize(types, name, temporary, options)
55
+ @columns_hash = {}
56
+ @indexes = {}
57
+ @native = types
58
+ @temporary = temporary
59
+ @options = options
60
+ @name = name
61
+ end
62
+
63
+ def columns; @columns_hash.values; end
64
+
65
+ # Appends a primary key definition to the table definition.
66
+ # Can be called multiple times, but this is probably not a good idea.
67
+ def primary_key(name, type = :primary_key, options = {})
68
+ column(name, type, options.merge(:primary_key => true))
69
+ end
70
+
71
+ # Returns a ColumnDefinition for the column with name +name+.
72
+ def [](name)
73
+ @columns_hash[name.to_s]
74
+ end
75
+
76
+ # Instantiates a new column for the table.
77
+ # The +type+ parameter is normally one of the migrations native types,
78
+ # which is one of the following:
79
+ # <tt>:primary_key</tt>, <tt>:string</tt>, <tt>:text</tt>,
80
+ # <tt>:integer</tt>, <tt>:float</tt>, <tt>:decimal</tt>,
81
+ # <tt>:datetime</tt>, <tt>:timestamp</tt>, <tt>:time</tt>,
82
+ # <tt>:date</tt>, <tt>:binary</tt>, <tt>:boolean</tt>.
83
+ #
84
+ # You may use a type not in this list as long as it is supported by your
85
+ # database (for example, "polygon" in MySQL), but this will not be database
86
+ # agnostic and should usually be avoided.
87
+ #
88
+ # Available options are (none of these exists by default):
89
+ # * <tt>:limit</tt> -
90
+ # Requests a maximum column length. This is number of characters for <tt>:string</tt> and
91
+ # <tt>:text</tt> columns and number of bytes for <tt>:binary</tt> and <tt>:integer</tt> columns.
92
+ # * <tt>:default</tt> -
93
+ # The column's default value. Use nil for NULL.
94
+ # * <tt>:null</tt> -
95
+ # Allows or disallows +NULL+ values in the column. This option could
96
+ # have been named <tt>:null_allowed</tt>.
97
+ # * <tt>:precision</tt> -
98
+ # Specifies the precision for a <tt>:decimal</tt> column.
99
+ # * <tt>:scale</tt> -
100
+ # Specifies the scale for a <tt>:decimal</tt> column.
101
+ #
102
+ # For clarity's sake: the precision is the number of significant digits,
103
+ # while the scale is the number of digits that can be stored following
104
+ # the decimal point. For example, the number 123.45 has a precision of 5
105
+ # and a scale of 2. A decimal with a precision of 5 and a scale of 2 can
106
+ # range from -999.99 to 999.99.
107
+ #
108
+ # Please be aware of different RDBMS implementations behavior with
109
+ # <tt>:decimal</tt> columns:
110
+ # * The SQL standard says the default scale should be 0, <tt>:scale</tt> <=
111
+ # <tt>:precision</tt>, and makes no comments about the requirements of
112
+ # <tt>:precision</tt>.
113
+ # * MySQL: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..30].
114
+ # Default is (10,0).
115
+ # * PostgreSQL: <tt>:precision</tt> [1..infinity],
116
+ # <tt>:scale</tt> [0..infinity]. No default.
117
+ # * SQLite2: Any <tt>:precision</tt> and <tt>:scale</tt> may be used.
118
+ # Internal storage as strings. No default.
119
+ # * SQLite3: No restrictions on <tt>:precision</tt> and <tt>:scale</tt>,
120
+ # but the maximum supported <tt>:precision</tt> is 16. No default.
121
+ # * Oracle: <tt>:precision</tt> [1..38], <tt>:scale</tt> [-84..127].
122
+ # Default is (38,0).
123
+ # * DB2: <tt>:precision</tt> [1..63], <tt>:scale</tt> [0..62].
124
+ # Default unknown.
125
+ # * Firebird: <tt>:precision</tt> [1..18], <tt>:scale</tt> [0..18].
126
+ # Default (9,0). Internal types NUMERIC and DECIMAL have different
127
+ # storage rules, decimal being better.
128
+ # * FrontBase?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
129
+ # Default (38,0). WARNING Max <tt>:precision</tt>/<tt>:scale</tt> for
130
+ # NUMERIC is 19, and DECIMAL is 38.
131
+ # * SqlServer?: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
132
+ # Default (38,0).
133
+ # * Sybase: <tt>:precision</tt> [1..38], <tt>:scale</tt> [0..38].
134
+ # Default (38,0).
135
+ # * OpenBase?: Documentation unclear. Claims storage in <tt>double</tt>.
136
+ #
137
+ # This method returns <tt>self</tt>.
138
+ #
139
+ # == Examples
140
+ # # Assuming +td+ is an instance of TableDefinition
141
+ # td.column(:granted, :boolean)
142
+ # # granted BOOLEAN
143
+ #
144
+ # td.column(:picture, :binary, limit: 2.megabytes)
145
+ # # => picture BLOB(2097152)
146
+ #
147
+ # td.column(:sales_stage, :string, limit: 20, default: 'new', null: false)
148
+ # # => sales_stage VARCHAR(20) DEFAULT 'new' NOT NULL
149
+ #
150
+ # td.column(:bill_gates_money, :decimal, precision: 15, scale: 2)
151
+ # # => bill_gates_money DECIMAL(15,2)
152
+ #
153
+ # td.column(:sensor_reading, :decimal, precision: 30, scale: 20)
154
+ # # => sensor_reading DECIMAL(30,20)
155
+ #
156
+ # # While <tt>:scale</tt> defaults to zero on most databases, it
157
+ # # probably wouldn't hurt to include it.
158
+ # td.column(:huge_integer, :decimal, precision: 30)
159
+ # # => huge_integer DECIMAL(30)
160
+ #
161
+ # # Defines a column with a database-specific type.
162
+ # td.column(:foo, 'polygon')
163
+ # # => foo polygon
164
+ #
165
+ # == Short-hand examples
166
+ #
167
+ # Instead of calling +column+ directly, you can also work with the short-hand definitions for the default types.
168
+ # They use the type as the method name instead of as a parameter and allow for multiple columns to be defined
169
+ # in a single statement.
170
+ #
171
+ # What can be written like this with the regular calls to column:
172
+ #
173
+ # create_table :products do |t|
174
+ # t.column :shop_id, :integer
175
+ # t.column :creator_id, :integer
176
+ # t.column :name, :string, default: "Untitled"
177
+ # t.column :value, :string, default: "Untitled"
178
+ # t.column :created_at, :datetime
179
+ # t.column :updated_at, :datetime
180
+ # end
181
+ #
182
+ # can also be written as follows using the short-hand:
183
+ #
184
+ # create_table :products do |t|
185
+ # t.integer :shop_id, :creator_id
186
+ # t.string :name, :value, default: "Untitled"
187
+ # t.timestamps
188
+ # end
189
+ #
190
+ # There's a short-hand method for each of the type values declared at the top. And then there's
191
+ # TableDefinition#timestamps that'll add +created_at+ and +updated_at+ as datetimes.
192
+ #
193
+ # TableDefinition#references will add an appropriately-named _id column, plus a corresponding _type
194
+ # column if the <tt>:polymorphic</tt> option is supplied. If <tt>:polymorphic</tt> is a hash of
195
+ # options, these will be used when creating the <tt>_type</tt> column. The <tt>:index</tt> option
196
+ # will also create an index, similar to calling <tt>add_index</tt>. So what can be written like this:
197
+ #
198
+ # create_table :taggings do |t|
199
+ # t.integer :tag_id, :tagger_id, :taggable_id
200
+ # t.string :tagger_type
201
+ # t.string :taggable_type, default: 'Photo'
202
+ # end
203
+ # add_index :taggings, :tag_id, name: 'index_taggings_on_tag_id'
204
+ # add_index :taggings, [:tagger_id, :tagger_type]
205
+ #
206
+ # Can also be written as follows using references:
207
+ #
208
+ # create_table :taggings do |t|
209
+ # t.references :tag, index: { name: 'index_taggings_on_tag_id' }
210
+ # t.references :tagger, polymorphic: true, index: true
211
+ # t.references :taggable, polymorphic: { default: 'Photo' }
212
+ # end
213
+ def column(name, type, options = {})
214
+ name = name.to_s
215
+ type = type.to_sym
216
+
217
+ if primary_key_column_name == name
218
+ raise ArgumentError, "you can't redefine the primary key column '#{name}'. To define a custom primary key, pass { id: false } to create_table."
219
+ end
220
+
221
+ @columns_hash[name] = new_column_definition(name, type, options)
222
+ self
223
+ end
224
+
225
+ def remove_column(name)
226
+ @columns_hash.delete name.to_s
227
+ end
228
+
229
+ [:string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean].each do |column_type|
230
+ define_method column_type do |*args|
231
+ options = args.extract_options!
232
+ column_names = args
233
+ column_names.each { |name| column(name, column_type, options) }
234
+ end
235
+ end
236
+
237
+ # Adds index options to the indexes hash, keyed by column name
238
+ # This is primarily used to track indexes that need to be created after the table
239
+ #
240
+ # index(:account_id, name: 'index_projects_on_account_id')
241
+ def index(column_name, options = {})
242
+ indexes[column_name] = options
243
+ end
244
+
245
+ # Appends <tt>:datetime</tt> columns <tt>:created_at</tt> and
246
+ # <tt>:updated_at</tt> to the table.
247
+ def timestamps(*args)
248
+ options = args.extract_options!
249
+ column(:created_at, :datetime, options)
250
+ column(:updated_at, :datetime, options)
251
+ end
252
+
253
+ def references(*args)
254
+ options = args.extract_options!
255
+ polymorphic = options.delete(:polymorphic)
256
+ index_options = options.delete(:index)
257
+ args.each do |col|
258
+ column("#{col}_id", :integer, options)
259
+ column("#{col}_type", :string, polymorphic.is_a?(Hash) ? polymorphic : options) if polymorphic
260
+ index(polymorphic ? %w(id type).map { |t| "#{col}_#{t}" } : "#{col}_id", index_options.is_a?(Hash) ? index_options : {}) if index_options
261
+ end
262
+ end
263
+ alias :belongs_to :references
264
+
265
+ def new_column_definition(name, type, options) # :nodoc:
266
+ column = create_column_definition name, type
267
+ limit = options.fetch(:limit) do
268
+ native[type][:limit] if native[type].is_a?(Hash)
269
+ end
270
+
271
+ column.limit = limit
272
+ column.array = options[:array] if column.respond_to?(:array)
273
+ column.precision = options[:precision]
274
+ column.scale = options[:scale]
275
+ column.default = options[:default]
276
+ column.null = options[:null]
277
+ column.first = options[:first]
278
+ column.after = options[:after]
279
+ column.primary_key = type == :primary_key || options[:primary_key]
280
+ column
281
+ end
282
+
283
+ private
284
+ def create_column_definition(name, type)
285
+ ColumnDefinition.new name, type
286
+ end
287
+
288
+ def primary_key_column_name
289
+ primary_key_column = columns.detect { |c| c.primary_key? }
290
+ primary_key_column && primary_key_column.name
291
+ end
292
+
293
+ def native
294
+ @native
295
+ end
296
+ end
297
+
298
+ class AlterTable # :nodoc:
299
+ attr_reader :adds
300
+
301
+ def initialize(td)
302
+ @td = td
303
+ @adds = []
304
+ end
305
+
306
+ def name; @td.name; end
307
+
308
+ def add_column(name, type, options)
309
+ name = name.to_s
310
+ type = type.to_sym
311
+ @adds << @td.new_column_definition(name, type, options)
312
+ end
313
+ end
314
+
315
+ # Represents an SQL table in an abstract way for updating a table.
316
+ # Also see TableDefinition and SchemaStatements#create_table
317
+ #
318
+ # Available transformations are:
319
+ #
320
+ # change_table :table do |t|
321
+ # t.column
322
+ # t.index
323
+ # t.rename_index
324
+ # t.timestamps
325
+ # t.change
326
+ # t.change_default
327
+ # t.rename
328
+ # t.references
329
+ # t.belongs_to
330
+ # t.string
331
+ # t.text
332
+ # t.integer
333
+ # t.float
334
+ # t.decimal
335
+ # t.datetime
336
+ # t.timestamp
337
+ # t.time
338
+ # t.date
339
+ # t.binary
340
+ # t.boolean
341
+ # t.remove
342
+ # t.remove_references
343
+ # t.remove_belongs_to
344
+ # t.remove_index
345
+ # t.remove_timestamps
346
+ # end
347
+ #
348
+ class Table
349
+ def initialize(table_name, base)
350
+ @table_name = table_name
351
+ @base = base
352
+ end
353
+
354
+ # Adds a new column to the named table.
355
+ # See TableDefinition#column for details of the options you can use.
356
+ #
357
+ # ====== Creating a simple column
358
+ # t.column(:name, :string)
359
+ def column(column_name, type, options = {})
360
+ @base.add_column(@table_name, column_name, type, options)
361
+ end
362
+
363
+ # Checks to see if a column exists. See SchemaStatements#column_exists?
364
+ def column_exists?(column_name, type = nil, options = {})
365
+ @base.column_exists?(@table_name, column_name, type, options)
366
+ end
367
+
368
+ # Adds a new index to the table. +column_name+ can be a single Symbol, or
369
+ # an Array of Symbols. See SchemaStatements#add_index
370
+ #
371
+ # ====== Creating a simple index
372
+ # t.index(:name)
373
+ # ====== Creating a unique index
374
+ # t.index([:branch_id, :party_id], unique: true)
375
+ # ====== Creating a named index
376
+ # t.index([:branch_id, :party_id], unique: true, name: 'by_branch_party')
377
+ def index(column_name, options = {})
378
+ @base.add_index(@table_name, column_name, options)
379
+ end
380
+
381
+ # Checks to see if an index exists. See SchemaStatements#index_exists?
382
+ def index_exists?(column_name, options = {})
383
+ @base.index_exists?(@table_name, column_name, options)
384
+ end
385
+
386
+ # Renames the given index on the table.
387
+ #
388
+ # t.rename_index(:user_id, :account_id)
389
+ def rename_index(index_name, new_index_name)
390
+ @base.rename_index(@table_name, index_name, new_index_name)
391
+ end
392
+
393
+ # Adds timestamps (+created_at+ and +updated_at+) columns to the table. See SchemaStatements#add_timestamps
394
+ #
395
+ # t.timestamps
396
+ def timestamps
397
+ @base.add_timestamps(@table_name)
398
+ end
399
+
400
+ # Changes the column's definition according to the new options.
401
+ # See TableDefinition#column for details of the options you can use.
402
+ #
403
+ # t.change(:name, :string, limit: 80)
404
+ # t.change(:description, :text)
405
+ def change(column_name, type, options = {})
406
+ @base.change_column(@table_name, column_name, type, options)
407
+ end
408
+
409
+ # Sets a new default value for a column. See SchemaStatements#change_column_default
410
+ #
411
+ # t.change_default(:qualification, 'new')
412
+ # t.change_default(:authorized, 1)
413
+ def change_default(column_name, default)
414
+ @base.change_column_default(@table_name, column_name, default)
415
+ end
416
+
417
+ # Removes the column(s) from the table definition.
418
+ #
419
+ # t.remove(:qualification)
420
+ # t.remove(:qualification, :experience)
421
+ def remove(*column_names)
422
+ @base.remove_columns(@table_name, *column_names)
423
+ end
424
+
425
+ # Removes the given index from the table.
426
+ #
427
+ # ====== Remove the index_table_name_on_column in the table_name table
428
+ # t.remove_index :column
429
+ # ====== Remove the index named index_table_name_on_branch_id in the table_name table
430
+ # t.remove_index column: :branch_id
431
+ # ====== Remove the index named index_table_name_on_branch_id_and_party_id in the table_name table
432
+ # t.remove_index column: [:branch_id, :party_id]
433
+ # ====== Remove the index named by_branch_party in the table_name table
434
+ # t.remove_index name: :by_branch_party
435
+ def remove_index(options = {})
436
+ @base.remove_index(@table_name, options)
437
+ end
438
+
439
+ # Removes the timestamp columns (+created_at+ and +updated_at+) from the table.
440
+ #
441
+ # t.remove_timestamps
442
+ def remove_timestamps
443
+ @base.remove_timestamps(@table_name)
444
+ end
445
+
446
+ # Renames a column.
447
+ #
448
+ # t.rename(:description, :name)
449
+ def rename(column_name, new_column_name)
450
+ @base.rename_column(@table_name, column_name, new_column_name)
451
+ end
452
+
453
+ # Adds a reference. Optionally adds a +type+ column, if <tt>:polymorphic</tt> option is provided.
454
+ # <tt>references</tt> and <tt>belongs_to</tt> are acceptable.
455
+ #
456
+ # t.references(:user)
457
+ # t.belongs_to(:supplier, polymorphic: true)
458
+ #
459
+ def references(*args)
460
+ options = args.extract_options!
461
+ args.each do |ref_name|
462
+ @base.add_reference(@table_name, ref_name, options)
463
+ end
464
+ end
465
+ alias :belongs_to :references
466
+
467
+ # Removes a reference. Optionally removes a +type+ column.
468
+ # <tt>remove_references</tt> and <tt>remove_belongs_to</tt> are acceptable.
469
+ #
470
+ # t.remove_references(:user)
471
+ # t.remove_belongs_to(:supplier, polymorphic: true)
472
+ #
473
+ def remove_references(*args)
474
+ options = args.extract_options!
475
+ args.each do |ref_name|
476
+ @base.remove_reference(@table_name, ref_name, options)
477
+ end
478
+ end
479
+ alias :remove_belongs_to :remove_references
480
+
481
+ # Adds a column or columns of a specified type
482
+ #
483
+ # t.string(:goat)
484
+ # t.string(:goat, :sheep)
485
+ [:string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean].each do |column_type|
486
+ define_method column_type do |*args|
487
+ options = args.extract_options!
488
+ args.each do |name|
489
+ @base.add_column(@table_name, name, column_type, options)
490
+ end
491
+ end
492
+ end
493
+
494
+ private
495
+ def native
496
+ @base.native_database_types
497
+ end
498
+ end
499
+
500
+ end
501
+ end
@@ -0,0 +1,70 @@
1
+ require 'ipaddr'
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters # :nodoc:
5
+ # The goal of this module is to move Adapter specific column
6
+ # definitions to the Adapter instead of having it in the schema
7
+ # dumper itself. This code represents the normal case.
8
+ # We can then redefine how certain data types may be handled in the schema dumper on the
9
+ # Adapter level by over-writing this code inside the database specific adapters
10
+ module ColumnDumper
11
+ def column_spec(column, types)
12
+ spec = prepare_column_options(column, types)
13
+ (spec.keys - [:name, :type]).each{ |k| spec[k].insert(0, "#{k.to_s}: ")}
14
+ spec
15
+ end
16
+
17
+ # This can be overridden on a Adapter level basis to support other
18
+ # extended datatypes (Example: Adding an array option in the
19
+ # PostgreSQLAdapter)
20
+ def prepare_column_options(column, types)
21
+ spec = {}
22
+ spec[:name] = column.name.inspect
23
+
24
+ # AR has an optimization which handles zero-scale decimals as integers. This
25
+ # code ensures that the dumper still dumps the column as a decimal.
26
+ spec[:type] = if column.type == :integer && /^(numeric|decimal)/ =~ column.sql_type
27
+ 'decimal'
28
+ else
29
+ column.type.to_s
30
+ end
31
+ spec[:limit] = column.limit.inspect if column.limit != types[column.type][:limit] && spec[:type] != 'decimal'
32
+ spec[:precision] = column.precision.inspect if column.precision
33
+ spec[:scale] = column.scale.inspect if column.scale
34
+ spec[:null] = 'false' unless column.null
35
+ spec[:default] = default_string(column.default) if column.has_default?
36
+ spec
37
+ end
38
+
39
+ # Lists the valid migration options
40
+ def migration_keys
41
+ [:name, :limit, :precision, :scale, :default, :null]
42
+ end
43
+
44
+ private
45
+
46
+ def default_string(value)
47
+ case value
48
+ when BigDecimal
49
+ value.to_s
50
+ when Date, DateTime, Time
51
+ "'#{value.to_s(:db)}'"
52
+ when Range
53
+ # infinity dumps as Infinity, which causes uninitialized constant error
54
+ value.inspect.gsub('Infinity', '::Float::INFINITY')
55
+ when IPAddr
56
+ subnet_mask = value.instance_variable_get(:@mask_addr)
57
+
58
+ # If the subnet mask is equal to /32, don't output it
59
+ if subnet_mask == (2**32 - 1)
60
+ "\"#{value.to_s}\""
61
+ else
62
+ "\"#{value.to_s}/#{subnet_mask.to_s(2).count('1')}\""
63
+ end
64
+ else
65
+ value.inspect
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end