activerecord 3.2.22.5 → 5.2.8

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 (275) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +657 -621
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +41 -46
  5. data/examples/performance.rb +55 -42
  6. data/examples/simple.rb +6 -5
  7. data/lib/active_record/aggregations.rb +264 -236
  8. data/lib/active_record/association_relation.rb +40 -0
  9. data/lib/active_record/associations/alias_tracker.rb +47 -42
  10. data/lib/active_record/associations/association.rb +127 -75
  11. data/lib/active_record/associations/association_scope.rb +126 -92
  12. data/lib/active_record/associations/belongs_to_association.rb +78 -27
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +9 -4
  14. data/lib/active_record/associations/builder/association.rb +117 -32
  15. data/lib/active_record/associations/builder/belongs_to.rb +135 -60
  16. data/lib/active_record/associations/builder/collection_association.rb +61 -54
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +120 -42
  18. data/lib/active_record/associations/builder/has_many.rb +10 -64
  19. data/lib/active_record/associations/builder/has_one.rb +19 -51
  20. data/lib/active_record/associations/builder/singular_association.rb +28 -18
  21. data/lib/active_record/associations/collection_association.rb +226 -293
  22. data/lib/active_record/associations/collection_proxy.rb +1067 -69
  23. data/lib/active_record/associations/foreign_association.rb +13 -0
  24. data/lib/active_record/associations/has_many_association.rb +83 -47
  25. data/lib/active_record/associations/has_many_through_association.rb +98 -65
  26. data/lib/active_record/associations/has_one_association.rb +57 -20
  27. data/lib/active_record/associations/has_one_through_association.rb +18 -9
  28. data/lib/active_record/associations/join_dependency/join_association.rb +48 -126
  29. data/lib/active_record/associations/join_dependency/join_base.rb +11 -12
  30. data/lib/active_record/associations/join_dependency/join_part.rb +35 -42
  31. data/lib/active_record/associations/join_dependency.rb +212 -164
  32. data/lib/active_record/associations/preloader/association.rb +95 -89
  33. data/lib/active_record/associations/preloader/through_association.rb +84 -44
  34. data/lib/active_record/associations/preloader.rb +123 -111
  35. data/lib/active_record/associations/singular_association.rb +33 -24
  36. data/lib/active_record/associations/through_association.rb +60 -26
  37. data/lib/active_record/associations.rb +1759 -1506
  38. data/lib/active_record/attribute_assignment.rb +60 -193
  39. data/lib/active_record/attribute_decorators.rb +90 -0
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +55 -8
  41. data/lib/active_record/attribute_methods/dirty.rb +113 -74
  42. data/lib/active_record/attribute_methods/primary_key.rb +106 -77
  43. data/lib/active_record/attribute_methods/query.rb +8 -5
  44. data/lib/active_record/attribute_methods/read.rb +63 -114
  45. data/lib/active_record/attribute_methods/serialization.rb +60 -90
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +69 -43
  47. data/lib/active_record/attribute_methods/write.rb +43 -45
  48. data/lib/active_record/attribute_methods.rb +366 -149
  49. data/lib/active_record/attributes.rb +266 -0
  50. data/lib/active_record/autosave_association.rb +312 -225
  51. data/lib/active_record/base.rb +114 -505
  52. data/lib/active_record/callbacks.rb +145 -67
  53. data/lib/active_record/coders/json.rb +15 -0
  54. data/lib/active_record/coders/yaml_column.rb +32 -23
  55. data/lib/active_record/collection_cache_key.rb +53 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +883 -284
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +16 -2
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +350 -200
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +82 -27
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +150 -65
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +23 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +146 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +477 -284
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +95 -0
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1100 -310
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +283 -0
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +450 -118
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +657 -446
  69. data/lib/active_record/connection_adapters/column.rb +50 -255
  70. data/lib/active_record/connection_adapters/connection_specification.rb +287 -0
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +33 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +140 -0
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +73 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +87 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +80 -0
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +148 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +35 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +59 -210
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +44 -0
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +163 -0
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +92 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +56 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +50 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +23 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +21 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +71 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +41 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +65 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +97 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +111 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +23 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +34 -0
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +168 -0
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +43 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +206 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +774 -0
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +81 -0
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +620 -1080
  117. data/lib/active_record/connection_adapters/schema_cache.rb +85 -36
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +34 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +67 -0
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +106 -0
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +545 -27
  126. data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
  127. data/lib/active_record/connection_handling.rb +145 -0
  128. data/lib/active_record/core.rb +559 -0
  129. data/lib/active_record/counter_cache.rb +200 -105
  130. data/lib/active_record/define_callbacks.rb +22 -0
  131. data/lib/active_record/dynamic_matchers.rb +107 -69
  132. data/lib/active_record/enum.rb +244 -0
  133. data/lib/active_record/errors.rb +245 -60
  134. data/lib/active_record/explain.rb +35 -71
  135. data/lib/active_record/explain_registry.rb +32 -0
  136. data/lib/active_record/explain_subscriber.rb +18 -9
  137. data/lib/active_record/fixture_set/file.rb +82 -0
  138. data/lib/active_record/fixtures.rb +418 -275
  139. data/lib/active_record/gem_version.rb +17 -0
  140. data/lib/active_record/inheritance.rb +209 -100
  141. data/lib/active_record/integration.rb +116 -21
  142. data/lib/active_record/internal_metadata.rb +45 -0
  143. data/lib/active_record/legacy_yaml_adapter.rb +48 -0
  144. data/lib/active_record/locale/en.yml +9 -1
  145. data/lib/active_record/locking/optimistic.rb +107 -94
  146. data/lib/active_record/locking/pessimistic.rb +20 -8
  147. data/lib/active_record/log_subscriber.rb +99 -34
  148. data/lib/active_record/migration/command_recorder.rb +199 -64
  149. data/lib/active_record/migration/compatibility.rb +217 -0
  150. data/lib/active_record/migration/join_table.rb +17 -0
  151. data/lib/active_record/migration.rb +893 -296
  152. data/lib/active_record/model_schema.rb +328 -175
  153. data/lib/active_record/nested_attributes.rb +338 -242
  154. data/lib/active_record/no_touching.rb +58 -0
  155. data/lib/active_record/null_relation.rb +68 -0
  156. data/lib/active_record/persistence.rb +557 -170
  157. data/lib/active_record/query_cache.rb +14 -43
  158. data/lib/active_record/querying.rb +36 -24
  159. data/lib/active_record/railtie.rb +147 -52
  160. data/lib/active_record/railties/console_sandbox.rb +5 -4
  161. data/lib/active_record/railties/controller_runtime.rb +13 -6
  162. data/lib/active_record/railties/databases.rake +206 -488
  163. data/lib/active_record/readonly_attributes.rb +4 -6
  164. data/lib/active_record/reflection.rb +734 -228
  165. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  166. data/lib/active_record/relation/batches.rb +249 -52
  167. data/lib/active_record/relation/calculations.rb +330 -284
  168. data/lib/active_record/relation/delegation.rb +135 -37
  169. data/lib/active_record/relation/finder_methods.rb +450 -287
  170. data/lib/active_record/relation/from_clause.rb +26 -0
  171. data/lib/active_record/relation/merger.rb +193 -0
  172. data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
  173. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  174. data/lib/active_record/relation/predicate_builder/base_handler.rb +19 -0
  175. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +20 -0
  176. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  177. data/lib/active_record/relation/predicate_builder/range_handler.rb +42 -0
  178. data/lib/active_record/relation/predicate_builder/relation_handler.rb +19 -0
  179. data/lib/active_record/relation/predicate_builder.rb +132 -43
  180. data/lib/active_record/relation/query_attribute.rb +45 -0
  181. data/lib/active_record/relation/query_methods.rb +1037 -221
  182. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  183. data/lib/active_record/relation/spawn_methods.rb +48 -151
  184. data/lib/active_record/relation/where_clause.rb +186 -0
  185. data/lib/active_record/relation/where_clause_factory.rb +34 -0
  186. data/lib/active_record/relation.rb +451 -359
  187. data/lib/active_record/result.rb +129 -20
  188. data/lib/active_record/runtime_registry.rb +24 -0
  189. data/lib/active_record/sanitization.rb +164 -136
  190. data/lib/active_record/schema.rb +31 -19
  191. data/lib/active_record/schema_dumper.rb +154 -107
  192. data/lib/active_record/schema_migration.rb +56 -0
  193. data/lib/active_record/scoping/default.rb +108 -98
  194. data/lib/active_record/scoping/named.rb +125 -112
  195. data/lib/active_record/scoping.rb +77 -123
  196. data/lib/active_record/secure_token.rb +40 -0
  197. data/lib/active_record/serialization.rb +10 -6
  198. data/lib/active_record/statement_cache.rb +121 -0
  199. data/lib/active_record/store.rb +175 -16
  200. data/lib/active_record/suppressor.rb +61 -0
  201. data/lib/active_record/table_metadata.rb +82 -0
  202. data/lib/active_record/tasks/database_tasks.rb +337 -0
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +115 -0
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +143 -0
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +83 -0
  206. data/lib/active_record/timestamp.rb +80 -41
  207. data/lib/active_record/touch_later.rb +64 -0
  208. data/lib/active_record/transactions.rb +240 -119
  209. data/lib/active_record/translation.rb +2 -0
  210. data/lib/active_record/type/adapter_specific_registry.rb +136 -0
  211. data/lib/active_record/type/date.rb +9 -0
  212. data/lib/active_record/type/date_time.rb +9 -0
  213. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  214. data/lib/active_record/type/hash_lookup_type_map.rb +25 -0
  215. data/lib/active_record/type/internal/timezone.rb +17 -0
  216. data/lib/active_record/type/json.rb +30 -0
  217. data/lib/active_record/type/serialized.rb +71 -0
  218. data/lib/active_record/type/text.rb +11 -0
  219. data/lib/active_record/type/time.rb +21 -0
  220. data/lib/active_record/type/type_map.rb +62 -0
  221. data/lib/active_record/type/unsigned_integer.rb +17 -0
  222. data/lib/active_record/type.rb +79 -0
  223. data/lib/active_record/type_caster/connection.rb +33 -0
  224. data/lib/active_record/type_caster/map.rb +23 -0
  225. data/lib/active_record/type_caster.rb +9 -0
  226. data/lib/active_record/validations/absence.rb +25 -0
  227. data/lib/active_record/validations/associated.rb +35 -18
  228. data/lib/active_record/validations/length.rb +26 -0
  229. data/lib/active_record/validations/presence.rb +68 -0
  230. data/lib/active_record/validations/uniqueness.rb +133 -75
  231. data/lib/active_record/validations.rb +53 -43
  232. data/lib/active_record/version.rb +7 -7
  233. data/lib/active_record.rb +89 -57
  234. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  235. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  236. data/lib/rails/generators/active_record/migration/migration_generator.rb +61 -8
  237. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
  238. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +46 -0
  239. data/lib/rails/generators/active_record/migration.rb +28 -8
  240. data/lib/rails/generators/active_record/model/model_generator.rb +23 -22
  241. data/lib/rails/generators/active_record/model/templates/model.rb.tt +13 -0
  242. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +1 -1
  243. data/lib/rails/generators/active_record.rb +10 -16
  244. metadata +141 -62
  245. data/examples/associations.png +0 -0
  246. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
  247. data/lib/active_record/associations/join_helper.rb +0 -55
  248. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  249. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  250. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  251. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  252. data/lib/active_record/associations/preloader/has_many_through.rb +0 -15
  253. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  254. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  255. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  256. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  257. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
  258. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -441
  259. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
  260. data/lib/active_record/dynamic_finder_match.rb +0 -68
  261. data/lib/active_record/dynamic_scope_match.rb +0 -23
  262. data/lib/active_record/fixtures/file.rb +0 -65
  263. data/lib/active_record/identity_map.rb +0 -162
  264. data/lib/active_record/observer.rb +0 -121
  265. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  266. data/lib/active_record/serializers/xml_serializer.rb +0 -203
  267. data/lib/active_record/session_store.rb +0 -360
  268. data/lib/active_record/test_case.rb +0 -73
  269. data/lib/rails/generators/active_record/migration/templates/migration.rb +0 -34
  270. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
  271. data/lib/rails/generators/active_record/model/templates/model.rb +0 -12
  272. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  273. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  274. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  275. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -0,0 +1,337 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Tasks # :nodoc:
5
+ class DatabaseAlreadyExists < StandardError; end # :nodoc:
6
+ class DatabaseNotSupported < StandardError; end # :nodoc:
7
+
8
+ # ActiveRecord::Tasks::DatabaseTasks is a utility class, which encapsulates
9
+ # logic behind common tasks used to manage database and migrations.
10
+ #
11
+ # The tasks defined here are used with Rake tasks provided by Active Record.
12
+ #
13
+ # In order to use DatabaseTasks, a few config values need to be set. All the needed
14
+ # config values are set by Rails already, so it's necessary to do it only if you
15
+ # want to change the defaults or when you want to use Active Record outside of Rails
16
+ # (in such case after configuring the database tasks, you can also use the rake tasks
17
+ # defined in Active Record).
18
+ #
19
+ # The possible config values are:
20
+ #
21
+ # * +env+: current environment (like Rails.env).
22
+ # * +database_configuration+: configuration of your databases (as in +config/database.yml+).
23
+ # * +db_dir+: your +db+ directory.
24
+ # * +fixtures_path+: a path to fixtures directory.
25
+ # * +migrations_paths+: a list of paths to directories with migrations.
26
+ # * +seed_loader+: an object which will load seeds, it needs to respond to the +load_seed+ method.
27
+ # * +root+: a path to the root of the application.
28
+ #
29
+ # Example usage of DatabaseTasks outside Rails could look as such:
30
+ #
31
+ # include ActiveRecord::Tasks
32
+ # DatabaseTasks.database_configuration = YAML.load_file('my_database_config.yml')
33
+ # DatabaseTasks.db_dir = 'db'
34
+ # # other settings...
35
+ #
36
+ # DatabaseTasks.create_current('production')
37
+ module DatabaseTasks
38
+ ##
39
+ # :singleton-method:
40
+ # Extra flags passed to database CLI tool (mysqldump/pg_dump) when calling db:structure:dump
41
+ mattr_accessor :structure_dump_flags, instance_accessor: false
42
+
43
+ ##
44
+ # :singleton-method:
45
+ # Extra flags passed to database CLI tool when calling db:structure:load
46
+ mattr_accessor :structure_load_flags, instance_accessor: false
47
+
48
+ extend self
49
+
50
+ attr_writer :current_config, :db_dir, :migrations_paths, :fixtures_path, :root, :env, :seed_loader
51
+ attr_accessor :database_configuration
52
+
53
+ LOCAL_HOSTS = ["127.0.0.1", "localhost"]
54
+
55
+ def check_protected_environments!
56
+ unless ENV["DISABLE_DATABASE_ENVIRONMENT_CHECK"]
57
+ current = ActiveRecord::Base.connection.migration_context.current_environment
58
+ stored = ActiveRecord::Base.connection.migration_context.last_stored_environment
59
+
60
+ if ActiveRecord::Base.connection.migration_context.protected_environment?
61
+ raise ActiveRecord::ProtectedEnvironmentError.new(stored)
62
+ end
63
+
64
+ if stored && stored != current
65
+ raise ActiveRecord::EnvironmentMismatchError.new(current: current, stored: stored)
66
+ end
67
+ end
68
+ rescue ActiveRecord::NoDatabaseError
69
+ end
70
+
71
+ def register_task(pattern, task)
72
+ @tasks ||= {}
73
+ @tasks[pattern] = task
74
+ end
75
+
76
+ register_task(/mysql/, "ActiveRecord::Tasks::MySQLDatabaseTasks")
77
+ register_task(/postgresql/, "ActiveRecord::Tasks::PostgreSQLDatabaseTasks")
78
+ register_task(/sqlite/, "ActiveRecord::Tasks::SQLiteDatabaseTasks")
79
+
80
+ def db_dir
81
+ @db_dir ||= Rails.application.config.paths["db"].first
82
+ end
83
+
84
+ def migrations_paths
85
+ @migrations_paths ||= Rails.application.paths["db/migrate"].to_a
86
+ end
87
+
88
+ def fixtures_path
89
+ @fixtures_path ||= if ENV["FIXTURES_PATH"]
90
+ File.join(root, ENV["FIXTURES_PATH"])
91
+ else
92
+ File.join(root, "test", "fixtures")
93
+ end
94
+ end
95
+
96
+ def root
97
+ @root ||= Rails.root
98
+ end
99
+
100
+ def env
101
+ @env ||= Rails.env
102
+ end
103
+
104
+ def seed_loader
105
+ @seed_loader ||= Rails.application
106
+ end
107
+
108
+ def current_config(options = {})
109
+ options.reverse_merge! env: env
110
+ if options.has_key?(:config)
111
+ @current_config = options[:config]
112
+ else
113
+ @current_config ||= ActiveRecord::Base.configurations[options[:env]]
114
+ end
115
+ end
116
+
117
+ def create(*arguments)
118
+ configuration = arguments.first
119
+ class_for_adapter(configuration["adapter"]).new(*arguments).create
120
+ $stdout.puts "Created database '#{configuration['database']}'"
121
+ rescue DatabaseAlreadyExists
122
+ $stderr.puts "Database '#{configuration['database']}' already exists"
123
+ rescue Exception => error
124
+ $stderr.puts error
125
+ $stderr.puts "Couldn't create '#{configuration['database']}' database. Please check your configuration."
126
+ raise
127
+ end
128
+
129
+ def create_all
130
+ old_pool = ActiveRecord::Base.connection_handler.retrieve_connection_pool(ActiveRecord::Base.connection_specification_name)
131
+ each_local_configuration { |configuration| create configuration }
132
+ if old_pool
133
+ ActiveRecord::Base.connection_handler.establish_connection(old_pool.spec.to_hash)
134
+ end
135
+ end
136
+
137
+ def create_current(environment = env)
138
+ each_current_configuration(environment) { |configuration|
139
+ create configuration
140
+ }
141
+ ActiveRecord::Base.establish_connection(environment.to_sym)
142
+ end
143
+
144
+ def drop(*arguments)
145
+ configuration = arguments.first
146
+ class_for_adapter(configuration["adapter"]).new(*arguments).drop
147
+ $stdout.puts "Dropped database '#{configuration['database']}'"
148
+ rescue ActiveRecord::NoDatabaseError
149
+ $stderr.puts "Database '#{configuration['database']}' does not exist"
150
+ rescue Exception => error
151
+ $stderr.puts error
152
+ $stderr.puts "Couldn't drop database '#{configuration['database']}'"
153
+ raise
154
+ end
155
+
156
+ def drop_all
157
+ each_local_configuration { |configuration| drop configuration }
158
+ end
159
+
160
+ def drop_current(environment = env)
161
+ each_current_configuration(environment) { |configuration|
162
+ drop configuration
163
+ }
164
+ end
165
+
166
+ def migrate
167
+ check_target_version
168
+
169
+ verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] != "false" : true
170
+ scope = ENV["SCOPE"]
171
+ verbose_was, Migration.verbose = Migration.verbose, verbose
172
+ Base.connection.migration_context.migrate(target_version) do |migration|
173
+ scope.blank? || scope == migration.scope
174
+ end
175
+ ActiveRecord::Base.clear_cache!
176
+ ensure
177
+ Migration.verbose = verbose_was
178
+ end
179
+
180
+ def check_target_version
181
+ if target_version && !(Migration::MigrationFilenameRegexp.match?(ENV["VERSION"]) || /\A\d+\z/.match?(ENV["VERSION"]))
182
+ raise "Invalid format of target version: `VERSION=#{ENV['VERSION']}`"
183
+ end
184
+ end
185
+
186
+ def target_version
187
+ ENV["VERSION"].to_i if ENV["VERSION"] && !ENV["VERSION"].empty?
188
+ end
189
+
190
+ def charset_current(environment = env)
191
+ charset ActiveRecord::Base.configurations[environment]
192
+ end
193
+
194
+ def charset(*arguments)
195
+ configuration = arguments.first
196
+ class_for_adapter(configuration["adapter"]).new(*arguments).charset
197
+ end
198
+
199
+ def collation_current(environment = env)
200
+ collation ActiveRecord::Base.configurations[environment]
201
+ end
202
+
203
+ def collation(*arguments)
204
+ configuration = arguments.first
205
+ class_for_adapter(configuration["adapter"]).new(*arguments).collation
206
+ end
207
+
208
+ def purge(configuration)
209
+ class_for_adapter(configuration["adapter"]).new(configuration).purge
210
+ end
211
+
212
+ def purge_all
213
+ each_local_configuration { |configuration|
214
+ purge configuration
215
+ }
216
+ end
217
+
218
+ def purge_current(environment = env)
219
+ each_current_configuration(environment) { |configuration|
220
+ purge configuration
221
+ }
222
+ ActiveRecord::Base.establish_connection(environment.to_sym)
223
+ end
224
+
225
+ def structure_dump(*arguments)
226
+ configuration = arguments.first
227
+ filename = arguments.delete_at 1
228
+ class_for_adapter(configuration["adapter"]).new(*arguments).structure_dump(filename, structure_dump_flags)
229
+ end
230
+
231
+ def structure_load(*arguments)
232
+ configuration = arguments.first
233
+ filename = arguments.delete_at 1
234
+ class_for_adapter(configuration["adapter"]).new(*arguments).structure_load(filename, structure_load_flags)
235
+ end
236
+
237
+ def load_schema(configuration, format = ActiveRecord::Base.schema_format, file = nil, environment = env) # :nodoc:
238
+ file ||= schema_file(format)
239
+
240
+ check_schema_file(file)
241
+ ActiveRecord::Base.establish_connection(configuration)
242
+
243
+ case format
244
+ when :ruby
245
+ load(file)
246
+ when :sql
247
+ structure_load(configuration, file)
248
+ else
249
+ raise ArgumentError, "unknown format #{format.inspect}"
250
+ end
251
+ ActiveRecord::InternalMetadata.create_table
252
+ ActiveRecord::InternalMetadata[:environment] = environment
253
+ end
254
+
255
+ def schema_file(format = ActiveRecord::Base.schema_format)
256
+ case format
257
+ when :ruby
258
+ File.join(db_dir, "schema.rb")
259
+ when :sql
260
+ File.join(db_dir, "structure.sql")
261
+ end
262
+ end
263
+
264
+ def load_schema_current(format = ActiveRecord::Base.schema_format, file = nil, environment = env)
265
+ each_current_configuration(environment) { |configuration, configuration_environment|
266
+ load_schema configuration, format, file, configuration_environment
267
+ }
268
+ ActiveRecord::Base.establish_connection(environment.to_sym)
269
+ end
270
+
271
+ def check_schema_file(filename)
272
+ unless File.exist?(filename)
273
+ message = %{#{filename} doesn't exist yet. Run `rails db:migrate` to create it, then try again.}.dup
274
+ message << %{ If you do not intend to use a database, you should instead alter #{Rails.root}/config/application.rb to limit the frameworks that will be loaded.} if defined?(::Rails.root)
275
+ Kernel.abort message
276
+ end
277
+ end
278
+
279
+ def load_seed
280
+ if seed_loader
281
+ seed_loader.load_seed
282
+ else
283
+ raise "You tried to load seed data, but no seed loader is specified. Please specify seed " \
284
+ "loader with ActiveRecord::Tasks::DatabaseTasks.seed_loader = your_seed_loader\n" \
285
+ "Seed loader should respond to load_seed method"
286
+ end
287
+ end
288
+
289
+ # Dumps the schema cache in YAML format for the connection into the file
290
+ #
291
+ # ==== Examples:
292
+ # ActiveRecord::Tasks::DatabaseTasks.dump_schema_cache(ActiveRecord::Base.connection, "tmp/schema_dump.yaml")
293
+ def dump_schema_cache(conn, filename)
294
+ conn.schema_cache.clear!
295
+ conn.data_sources.each { |table| conn.schema_cache.add(table) }
296
+ open(filename, "wb") { |f| f.write(YAML.dump(conn.schema_cache)) }
297
+ end
298
+
299
+ private
300
+
301
+ def class_for_adapter(adapter)
302
+ _key, task = @tasks.each_pair.detect { |pattern, _task| adapter[pattern] }
303
+ unless task
304
+ raise DatabaseNotSupported, "Rake tasks not supported by '#{adapter}' adapter"
305
+ end
306
+ task.is_a?(String) ? task.constantize : task
307
+ end
308
+
309
+ def each_current_configuration(environment)
310
+ environments = [environment]
311
+ environments << "test" if environment == "development"
312
+
313
+ ActiveRecord::Base.configurations.slice(*environments).each do |configuration_environment, configuration|
314
+ next unless configuration["database"]
315
+
316
+ yield configuration, configuration_environment
317
+ end
318
+ end
319
+
320
+ def each_local_configuration
321
+ ActiveRecord::Base.configurations.each_value do |configuration|
322
+ next unless configuration["database"]
323
+
324
+ if local_database?(configuration)
325
+ yield configuration
326
+ else
327
+ $stderr.puts "This task only modifies local databases. #{configuration['database']} is on a remote host."
328
+ end
329
+ end
330
+ end
331
+
332
+ def local_database?(configuration)
333
+ configuration["host"].blank? || LOCAL_HOSTS.include?(configuration["host"])
334
+ end
335
+ end
336
+ end
337
+ end
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Tasks # :nodoc:
5
+ class MySQLDatabaseTasks # :nodoc:
6
+ delegate :connection, :establish_connection, to: ActiveRecord::Base
7
+
8
+ def initialize(configuration)
9
+ @configuration = configuration
10
+ end
11
+
12
+ def create
13
+ establish_connection configuration_without_database
14
+ connection.create_database configuration["database"], creation_options
15
+ establish_connection configuration
16
+ rescue ActiveRecord::StatementInvalid => error
17
+ if error.message.include?("database exists")
18
+ raise DatabaseAlreadyExists
19
+ else
20
+ raise
21
+ end
22
+ end
23
+
24
+ def drop
25
+ establish_connection configuration
26
+ connection.drop_database configuration["database"]
27
+ end
28
+
29
+ def purge
30
+ establish_connection configuration
31
+ connection.recreate_database configuration["database"], creation_options
32
+ end
33
+
34
+ def charset
35
+ connection.charset
36
+ end
37
+
38
+ def collation
39
+ connection.collation
40
+ end
41
+
42
+ def structure_dump(filename, extra_flags)
43
+ args = prepare_command_options
44
+ args.concat(["--result-file", "#{filename}"])
45
+ args.concat(["--no-data"])
46
+ args.concat(["--routines"])
47
+ args.concat(["--skip-comments"])
48
+
49
+ ignore_tables = ActiveRecord::SchemaDumper.ignore_tables
50
+ if ignore_tables.any?
51
+ args += ignore_tables.map { |table| "--ignore-table=#{configuration['database']}.#{table}" }
52
+ end
53
+
54
+ args.concat(["#{configuration['database']}"])
55
+ args.unshift(*extra_flags) if extra_flags
56
+
57
+ run_cmd("mysqldump", args, "dumping")
58
+ end
59
+
60
+ def structure_load(filename, extra_flags)
61
+ args = prepare_command_options
62
+ args.concat(["--execute", %{SET FOREIGN_KEY_CHECKS = 0; SOURCE #{filename}; SET FOREIGN_KEY_CHECKS = 1}])
63
+ args.concat(["--database", "#{configuration['database']}"])
64
+ args.unshift(*extra_flags) if extra_flags
65
+
66
+ run_cmd("mysql", args, "loading")
67
+ end
68
+
69
+ private
70
+
71
+ def configuration
72
+ @configuration
73
+ end
74
+
75
+ def configuration_without_database
76
+ configuration.merge("database" => nil)
77
+ end
78
+
79
+ def creation_options
80
+ Hash.new.tap do |options|
81
+ options[:charset] = configuration["encoding"] if configuration.include? "encoding"
82
+ options[:collation] = configuration["collation"] if configuration.include? "collation"
83
+ end
84
+ end
85
+
86
+ def prepare_command_options
87
+ args = {
88
+ "host" => "--host",
89
+ "port" => "--port",
90
+ "socket" => "--socket",
91
+ "username" => "--user",
92
+ "password" => "--password",
93
+ "encoding" => "--default-character-set",
94
+ "sslca" => "--ssl-ca",
95
+ "sslcert" => "--ssl-cert",
96
+ "sslcapath" => "--ssl-capath",
97
+ "sslcipher" => "--ssl-cipher",
98
+ "sslkey" => "--ssl-key"
99
+ }.map { |opt, arg| "#{arg}=#{configuration[opt]}" if configuration[opt] }.compact
100
+
101
+ args
102
+ end
103
+
104
+ def run_cmd(cmd, args, action)
105
+ fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
106
+ end
107
+
108
+ def run_cmd_error(cmd, args, action)
109
+ msg = "failed to execute: `#{cmd}`\n".dup
110
+ msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
111
+ msg
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "tempfile"
4
+
5
+ module ActiveRecord
6
+ module Tasks # :nodoc:
7
+ class PostgreSQLDatabaseTasks # :nodoc:
8
+ DEFAULT_ENCODING = ENV["CHARSET"] || "utf8"
9
+ ON_ERROR_STOP_1 = "ON_ERROR_STOP=1".freeze
10
+ SQL_COMMENT_BEGIN = "--".freeze
11
+
12
+ delegate :connection, :establish_connection, :clear_active_connections!,
13
+ to: ActiveRecord::Base
14
+
15
+ def initialize(configuration)
16
+ @configuration = configuration
17
+ end
18
+
19
+ def create(master_established = false)
20
+ establish_master_connection unless master_established
21
+ connection.create_database configuration["database"],
22
+ configuration.merge("encoding" => encoding)
23
+ establish_connection configuration
24
+ rescue ActiveRecord::StatementInvalid => error
25
+ if error.cause.is_a?(PG::DuplicateDatabase)
26
+ raise DatabaseAlreadyExists
27
+ else
28
+ raise
29
+ end
30
+ end
31
+
32
+ def drop
33
+ establish_master_connection
34
+ connection.drop_database configuration["database"]
35
+ end
36
+
37
+ def charset
38
+ connection.encoding
39
+ end
40
+
41
+ def collation
42
+ connection.collation
43
+ end
44
+
45
+ def purge
46
+ clear_active_connections!
47
+ drop
48
+ create true
49
+ end
50
+
51
+ def structure_dump(filename, extra_flags)
52
+ set_psql_env
53
+
54
+ search_path = \
55
+ case ActiveRecord::Base.dump_schemas
56
+ when :schema_search_path
57
+ configuration["schema_search_path"]
58
+ when :all
59
+ nil
60
+ when String
61
+ ActiveRecord::Base.dump_schemas
62
+ end
63
+
64
+ args = ["-s", "-x", "-O", "-f", filename]
65
+ args.concat(Array(extra_flags)) if extra_flags
66
+ unless search_path.blank?
67
+ args += search_path.split(",").map do |part|
68
+ "--schema=#{part.strip}"
69
+ end
70
+ end
71
+
72
+ ignore_tables = ActiveRecord::SchemaDumper.ignore_tables
73
+ if ignore_tables.any?
74
+ args += ignore_tables.flat_map { |table| ["-T", table] }
75
+ end
76
+
77
+ args << configuration["database"]
78
+ run_cmd("pg_dump", args, "dumping")
79
+ remove_sql_header_comments(filename)
80
+ File.open(filename, "a") { |f| f << "SET search_path TO #{connection.schema_search_path};\n\n" }
81
+ end
82
+
83
+ def structure_load(filename, extra_flags)
84
+ set_psql_env
85
+ args = ["-v", ON_ERROR_STOP_1, "-q", "-f", filename]
86
+ args.concat(Array(extra_flags)) if extra_flags
87
+ args << configuration["database"]
88
+ run_cmd("psql", args, "loading")
89
+ end
90
+
91
+ private
92
+
93
+ def configuration
94
+ @configuration
95
+ end
96
+
97
+ def encoding
98
+ configuration["encoding"] || DEFAULT_ENCODING
99
+ end
100
+
101
+ def establish_master_connection
102
+ establish_connection configuration.merge(
103
+ "database" => "postgres",
104
+ "schema_search_path" => "public"
105
+ )
106
+ end
107
+
108
+ def set_psql_env
109
+ ENV["PGHOST"] = configuration["host"] if configuration["host"]
110
+ ENV["PGPORT"] = configuration["port"].to_s if configuration["port"]
111
+ ENV["PGPASSWORD"] = configuration["password"].to_s if configuration["password"]
112
+ ENV["PGUSER"] = configuration["username"].to_s if configuration["username"]
113
+ end
114
+
115
+ def run_cmd(cmd, args, action)
116
+ fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
117
+ end
118
+
119
+ def run_cmd_error(cmd, args, action)
120
+ msg = "failed to execute:\n".dup
121
+ msg << "#{cmd} #{args.join(' ')}\n\n"
122
+ msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
123
+ msg
124
+ end
125
+
126
+ def remove_sql_header_comments(filename)
127
+ removing_comments = true
128
+ tempfile = Tempfile.open("uncommented_structure.sql")
129
+ begin
130
+ File.foreach(filename) do |line|
131
+ unless removing_comments && (line.start_with?(SQL_COMMENT_BEGIN) || line.blank?)
132
+ tempfile << line
133
+ removing_comments = false
134
+ end
135
+ end
136
+ ensure
137
+ tempfile.close
138
+ end
139
+ FileUtils.cp(tempfile.path, filename)
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Tasks # :nodoc:
5
+ class SQLiteDatabaseTasks # :nodoc:
6
+ delegate :connection, :establish_connection, to: ActiveRecord::Base
7
+
8
+ def initialize(configuration, root = ActiveRecord::Tasks::DatabaseTasks.root)
9
+ @configuration, @root = configuration, root
10
+ end
11
+
12
+ def create
13
+ raise DatabaseAlreadyExists if File.exist?(configuration["database"])
14
+
15
+ establish_connection configuration
16
+ connection
17
+ end
18
+
19
+ def drop
20
+ require "pathname"
21
+ path = Pathname.new configuration["database"]
22
+ file = path.absolute? ? path.to_s : File.join(root, path)
23
+
24
+ FileUtils.rm(file)
25
+ rescue Errno::ENOENT => error
26
+ raise NoDatabaseError.new(error.message)
27
+ end
28
+
29
+ def purge
30
+ drop
31
+ rescue NoDatabaseError
32
+ ensure
33
+ create
34
+ end
35
+
36
+ def charset
37
+ connection.encoding
38
+ end
39
+
40
+ def structure_dump(filename, extra_flags)
41
+ args = []
42
+ args.concat(Array(extra_flags)) if extra_flags
43
+ args << configuration["database"]
44
+
45
+ ignore_tables = ActiveRecord::SchemaDumper.ignore_tables
46
+ if ignore_tables.any?
47
+ condition = ignore_tables.map { |table| connection.quote(table) }.join(", ")
48
+ args << "SELECT sql FROM sqlite_master WHERE tbl_name NOT IN (#{condition}) ORDER BY tbl_name, type DESC, name"
49
+ else
50
+ args << ".schema"
51
+ end
52
+ run_cmd("sqlite3", args, filename)
53
+ end
54
+
55
+ def structure_load(filename, extra_flags)
56
+ dbfile = configuration["database"]
57
+ flags = extra_flags.join(" ") if extra_flags
58
+ `sqlite3 #{flags} #{dbfile} < "#{filename}"`
59
+ end
60
+
61
+ private
62
+
63
+ def configuration
64
+ @configuration
65
+ end
66
+
67
+ def root
68
+ @root
69
+ end
70
+
71
+ def run_cmd(cmd, args, out)
72
+ fail run_cmd_error(cmd, args) unless Kernel.system(cmd, *args, out: out)
73
+ end
74
+
75
+ def run_cmd_error(cmd, args)
76
+ msg = "failed to execute:\n".dup
77
+ msg << "#{cmd} #{args.join(' ')}\n\n"
78
+ msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
79
+ msg
80
+ end
81
+ end
82
+ end
83
+ end