activerecord 5.2.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 (244) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +937 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +217 -0
  5. data/examples/performance.rb +185 -0
  6. data/examples/simple.rb +15 -0
  7. data/lib/active_record.rb +188 -0
  8. data/lib/active_record/aggregations.rb +283 -0
  9. data/lib/active_record/association_relation.rb +40 -0
  10. data/lib/active_record/associations.rb +1860 -0
  11. data/lib/active_record/associations/alias_tracker.rb +81 -0
  12. data/lib/active_record/associations/association.rb +299 -0
  13. data/lib/active_record/associations/association_scope.rb +168 -0
  14. data/lib/active_record/associations/belongs_to_association.rb +130 -0
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +40 -0
  16. data/lib/active_record/associations/builder/association.rb +140 -0
  17. data/lib/active_record/associations/builder/belongs_to.rb +163 -0
  18. data/lib/active_record/associations/builder/collection_association.rb +82 -0
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +135 -0
  20. data/lib/active_record/associations/builder/has_many.rb +17 -0
  21. data/lib/active_record/associations/builder/has_one.rb +30 -0
  22. data/lib/active_record/associations/builder/singular_association.rb +42 -0
  23. data/lib/active_record/associations/collection_association.rb +513 -0
  24. data/lib/active_record/associations/collection_proxy.rb +1131 -0
  25. data/lib/active_record/associations/foreign_association.rb +13 -0
  26. data/lib/active_record/associations/has_many_association.rb +144 -0
  27. data/lib/active_record/associations/has_many_through_association.rb +227 -0
  28. data/lib/active_record/associations/has_one_association.rb +120 -0
  29. data/lib/active_record/associations/has_one_through_association.rb +45 -0
  30. data/lib/active_record/associations/join_dependency.rb +262 -0
  31. data/lib/active_record/associations/join_dependency/join_association.rb +60 -0
  32. data/lib/active_record/associations/join_dependency/join_base.rb +23 -0
  33. data/lib/active_record/associations/join_dependency/join_part.rb +71 -0
  34. data/lib/active_record/associations/preloader.rb +193 -0
  35. data/lib/active_record/associations/preloader/association.rb +131 -0
  36. data/lib/active_record/associations/preloader/through_association.rb +107 -0
  37. data/lib/active_record/associations/singular_association.rb +73 -0
  38. data/lib/active_record/associations/through_association.rb +121 -0
  39. data/lib/active_record/attribute_assignment.rb +88 -0
  40. data/lib/active_record/attribute_decorators.rb +90 -0
  41. data/lib/active_record/attribute_methods.rb +492 -0
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +78 -0
  43. data/lib/active_record/attribute_methods/dirty.rb +150 -0
  44. data/lib/active_record/attribute_methods/primary_key.rb +143 -0
  45. data/lib/active_record/attribute_methods/query.rb +42 -0
  46. data/lib/active_record/attribute_methods/read.rb +85 -0
  47. data/lib/active_record/attribute_methods/serialization.rb +90 -0
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +91 -0
  49. data/lib/active_record/attribute_methods/write.rb +68 -0
  50. data/lib/active_record/attributes.rb +266 -0
  51. data/lib/active_record/autosave_association.rb +498 -0
  52. data/lib/active_record/base.rb +329 -0
  53. data/lib/active_record/callbacks.rb +353 -0
  54. data/lib/active_record/coders/json.rb +15 -0
  55. data/lib/active_record/coders/yaml_column.rb +50 -0
  56. data/lib/active_record/collection_cache_key.rb +53 -0
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +1068 -0
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +72 -0
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +540 -0
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +145 -0
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +200 -0
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +23 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +146 -0
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +685 -0
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +95 -0
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1396 -0
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +283 -0
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +628 -0
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +887 -0
  70. data/lib/active_record/connection_adapters/column.rb +91 -0
  71. data/lib/active_record/connection_adapters/connection_specification.rb +287 -0
  72. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +33 -0
  73. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  74. data/lib/active_record/connection_adapters/mysql/database_statements.rb +140 -0
  75. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  76. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +73 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +87 -0
  79. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +80 -0
  80. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +148 -0
  81. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +35 -0
  82. data/lib/active_record/connection_adapters/mysql2_adapter.rb +129 -0
  83. data/lib/active_record/connection_adapters/postgresql/column.rb +44 -0
  84. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +163 -0
  85. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid.rb +34 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +92 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +56 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +50 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +23 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +21 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +71 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +41 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +65 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +97 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +111 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +23 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
  109. data/lib/active_record/connection_adapters/postgresql/quoting.rb +168 -0
  110. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +43 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +206 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  114. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +774 -0
  115. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
  116. data/lib/active_record/connection_adapters/postgresql/utils.rb +81 -0
  117. data/lib/active_record/connection_adapters/postgresql_adapter.rb +863 -0
  118. data/lib/active_record/connection_adapters/schema_cache.rb +118 -0
  119. data/lib/active_record/connection_adapters/sql_type_metadata.rb +34 -0
  120. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  121. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +67 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  125. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +106 -0
  126. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +573 -0
  127. data/lib/active_record/connection_adapters/statement_pool.rb +61 -0
  128. data/lib/active_record/connection_handling.rb +145 -0
  129. data/lib/active_record/core.rb +559 -0
  130. data/lib/active_record/counter_cache.rb +218 -0
  131. data/lib/active_record/define_callbacks.rb +22 -0
  132. data/lib/active_record/dynamic_matchers.rb +122 -0
  133. data/lib/active_record/enum.rb +244 -0
  134. data/lib/active_record/errors.rb +380 -0
  135. data/lib/active_record/explain.rb +50 -0
  136. data/lib/active_record/explain_registry.rb +32 -0
  137. data/lib/active_record/explain_subscriber.rb +34 -0
  138. data/lib/active_record/fixture_set/file.rb +82 -0
  139. data/lib/active_record/fixtures.rb +1065 -0
  140. data/lib/active_record/gem_version.rb +17 -0
  141. data/lib/active_record/inheritance.rb +283 -0
  142. data/lib/active_record/integration.rb +155 -0
  143. data/lib/active_record/internal_metadata.rb +45 -0
  144. data/lib/active_record/legacy_yaml_adapter.rb +48 -0
  145. data/lib/active_record/locale/en.yml +48 -0
  146. data/lib/active_record/locking/optimistic.rb +198 -0
  147. data/lib/active_record/locking/pessimistic.rb +89 -0
  148. data/lib/active_record/log_subscriber.rb +137 -0
  149. data/lib/active_record/migration.rb +1378 -0
  150. data/lib/active_record/migration/command_recorder.rb +240 -0
  151. data/lib/active_record/migration/compatibility.rb +217 -0
  152. data/lib/active_record/migration/join_table.rb +17 -0
  153. data/lib/active_record/model_schema.rb +521 -0
  154. data/lib/active_record/nested_attributes.rb +600 -0
  155. data/lib/active_record/no_touching.rb +58 -0
  156. data/lib/active_record/null_relation.rb +68 -0
  157. data/lib/active_record/persistence.rb +763 -0
  158. data/lib/active_record/query_cache.rb +45 -0
  159. data/lib/active_record/querying.rb +70 -0
  160. data/lib/active_record/railtie.rb +226 -0
  161. data/lib/active_record/railties/console_sandbox.rb +7 -0
  162. data/lib/active_record/railties/controller_runtime.rb +56 -0
  163. data/lib/active_record/railties/databases.rake +377 -0
  164. data/lib/active_record/readonly_attributes.rb +24 -0
  165. data/lib/active_record/reflection.rb +1044 -0
  166. data/lib/active_record/relation.rb +629 -0
  167. data/lib/active_record/relation/batches.rb +287 -0
  168. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  169. data/lib/active_record/relation/calculations.rb +417 -0
  170. data/lib/active_record/relation/delegation.rb +147 -0
  171. data/lib/active_record/relation/finder_methods.rb +565 -0
  172. data/lib/active_record/relation/from_clause.rb +26 -0
  173. data/lib/active_record/relation/merger.rb +193 -0
  174. data/lib/active_record/relation/predicate_builder.rb +152 -0
  175. data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
  176. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  177. data/lib/active_record/relation/predicate_builder/base_handler.rb +19 -0
  178. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +20 -0
  179. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  180. data/lib/active_record/relation/predicate_builder/range_handler.rb +42 -0
  181. data/lib/active_record/relation/predicate_builder/relation_handler.rb +19 -0
  182. data/lib/active_record/relation/query_attribute.rb +45 -0
  183. data/lib/active_record/relation/query_methods.rb +1231 -0
  184. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  185. data/lib/active_record/relation/spawn_methods.rb +77 -0
  186. data/lib/active_record/relation/where_clause.rb +186 -0
  187. data/lib/active_record/relation/where_clause_factory.rb +34 -0
  188. data/lib/active_record/result.rb +149 -0
  189. data/lib/active_record/runtime_registry.rb +24 -0
  190. data/lib/active_record/sanitization.rb +222 -0
  191. data/lib/active_record/schema.rb +70 -0
  192. data/lib/active_record/schema_dumper.rb +255 -0
  193. data/lib/active_record/schema_migration.rb +56 -0
  194. data/lib/active_record/scoping.rb +106 -0
  195. data/lib/active_record/scoping/default.rb +152 -0
  196. data/lib/active_record/scoping/named.rb +213 -0
  197. data/lib/active_record/secure_token.rb +40 -0
  198. data/lib/active_record/serialization.rb +22 -0
  199. data/lib/active_record/statement_cache.rb +121 -0
  200. data/lib/active_record/store.rb +211 -0
  201. data/lib/active_record/suppressor.rb +61 -0
  202. data/lib/active_record/table_metadata.rb +82 -0
  203. data/lib/active_record/tasks/database_tasks.rb +337 -0
  204. data/lib/active_record/tasks/mysql_database_tasks.rb +115 -0
  205. data/lib/active_record/tasks/postgresql_database_tasks.rb +143 -0
  206. data/lib/active_record/tasks/sqlite_database_tasks.rb +83 -0
  207. data/lib/active_record/timestamp.rb +153 -0
  208. data/lib/active_record/touch_later.rb +64 -0
  209. data/lib/active_record/transactions.rb +502 -0
  210. data/lib/active_record/translation.rb +24 -0
  211. data/lib/active_record/type.rb +79 -0
  212. data/lib/active_record/type/adapter_specific_registry.rb +136 -0
  213. data/lib/active_record/type/date.rb +9 -0
  214. data/lib/active_record/type/date_time.rb +9 -0
  215. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  216. data/lib/active_record/type/hash_lookup_type_map.rb +25 -0
  217. data/lib/active_record/type/internal/timezone.rb +17 -0
  218. data/lib/active_record/type/json.rb +30 -0
  219. data/lib/active_record/type/serialized.rb +71 -0
  220. data/lib/active_record/type/text.rb +11 -0
  221. data/lib/active_record/type/time.rb +21 -0
  222. data/lib/active_record/type/type_map.rb +62 -0
  223. data/lib/active_record/type/unsigned_integer.rb +17 -0
  224. data/lib/active_record/type_caster.rb +9 -0
  225. data/lib/active_record/type_caster/connection.rb +33 -0
  226. data/lib/active_record/type_caster/map.rb +23 -0
  227. data/lib/active_record/validations.rb +93 -0
  228. data/lib/active_record/validations/absence.rb +25 -0
  229. data/lib/active_record/validations/associated.rb +60 -0
  230. data/lib/active_record/validations/length.rb +26 -0
  231. data/lib/active_record/validations/presence.rb +68 -0
  232. data/lib/active_record/validations/uniqueness.rb +238 -0
  233. data/lib/active_record/version.rb +10 -0
  234. data/lib/rails/generators/active_record.rb +19 -0
  235. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  236. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  237. data/lib/rails/generators/active_record/migration.rb +35 -0
  238. data/lib/rails/generators/active_record/migration/migration_generator.rb +78 -0
  239. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
  240. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +46 -0
  241. data/lib/rails/generators/active_record/model/model_generator.rb +48 -0
  242. data/lib/rails/generators/active_record/model/templates/model.rb.tt +13 -0
  243. data/lib/rails/generators/active_record/model/templates/module.rb.tt +7 -0
  244. metadata +333 -0
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+ class StatementPool # :nodoc:
6
+ include Enumerable
7
+
8
+ DEFAULT_STATEMENT_LIMIT = 1000
9
+
10
+ def initialize(statement_limit = nil)
11
+ @cache = Hash.new { |h, pid| h[pid] = {} }
12
+ @statement_limit = statement_limit || DEFAULT_STATEMENT_LIMIT
13
+ end
14
+
15
+ def each(&block)
16
+ cache.each(&block)
17
+ end
18
+
19
+ def key?(key)
20
+ cache.key?(key)
21
+ end
22
+
23
+ def [](key)
24
+ cache[key]
25
+ end
26
+
27
+ def length
28
+ cache.length
29
+ end
30
+
31
+ def []=(sql, stmt)
32
+ while @statement_limit <= cache.size
33
+ dealloc(cache.shift.last)
34
+ end
35
+ cache[sql] = stmt
36
+ end
37
+
38
+ def clear
39
+ cache.each_value do |stmt|
40
+ dealloc stmt
41
+ end
42
+ cache.clear
43
+ end
44
+
45
+ def delete(key)
46
+ dealloc cache[key]
47
+ cache.delete(key)
48
+ end
49
+
50
+ private
51
+
52
+ def cache
53
+ @cache[Process.pid]
54
+ end
55
+
56
+ def dealloc(stmt)
57
+ raise NotImplementedError
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module ConnectionHandling
5
+ RAILS_ENV = -> { (Rails.env if defined?(Rails.env)) || ENV["RAILS_ENV"].presence || ENV["RACK_ENV"].presence }
6
+ DEFAULT_ENV = -> { RAILS_ENV.call || "default_env" }
7
+
8
+ # Establishes the connection to the database. Accepts a hash as input where
9
+ # the <tt>:adapter</tt> key must be specified with the name of a database adapter (in lower-case)
10
+ # example for regular databases (MySQL, PostgreSQL, etc):
11
+ #
12
+ # ActiveRecord::Base.establish_connection(
13
+ # adapter: "mysql2",
14
+ # host: "localhost",
15
+ # username: "myuser",
16
+ # password: "mypass",
17
+ # database: "somedatabase"
18
+ # )
19
+ #
20
+ # Example for SQLite database:
21
+ #
22
+ # ActiveRecord::Base.establish_connection(
23
+ # adapter: "sqlite3",
24
+ # database: "path/to/dbfile"
25
+ # )
26
+ #
27
+ # Also accepts keys as strings (for parsing from YAML for example):
28
+ #
29
+ # ActiveRecord::Base.establish_connection(
30
+ # "adapter" => "sqlite3",
31
+ # "database" => "path/to/dbfile"
32
+ # )
33
+ #
34
+ # Or a URL:
35
+ #
36
+ # ActiveRecord::Base.establish_connection(
37
+ # "postgres://myuser:mypass@localhost/somedatabase"
38
+ # )
39
+ #
40
+ # In case {ActiveRecord::Base.configurations}[rdoc-ref:Core.configurations]
41
+ # is set (Rails automatically loads the contents of config/database.yml into it),
42
+ # a symbol can also be given as argument, representing a key in the
43
+ # configuration hash:
44
+ #
45
+ # ActiveRecord::Base.establish_connection(:production)
46
+ #
47
+ # The exceptions AdapterNotSpecified, AdapterNotFound and +ArgumentError+
48
+ # may be returned on an error.
49
+ def establish_connection(config = nil)
50
+ raise "Anonymous class is not allowed." unless name
51
+
52
+ config ||= DEFAULT_ENV.call.to_sym
53
+ spec_name = self == Base ? "primary" : name
54
+ self.connection_specification_name = spec_name
55
+
56
+ resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new(Base.configurations)
57
+ spec = resolver.resolve(config).symbolize_keys
58
+ spec[:name] = spec_name
59
+
60
+ connection_handler.establish_connection(spec)
61
+ end
62
+
63
+ class MergeAndResolveDefaultUrlConfig # :nodoc:
64
+ def initialize(raw_configurations)
65
+ @raw_config = raw_configurations.dup
66
+ @env = DEFAULT_ENV.call.to_s
67
+ end
68
+
69
+ # Returns fully resolved connection hashes.
70
+ # Merges connection information from `ENV['DATABASE_URL']` if available.
71
+ def resolve
72
+ ConnectionAdapters::ConnectionSpecification::Resolver.new(config).resolve_all
73
+ end
74
+
75
+ private
76
+ def config
77
+ @raw_config.dup.tap do |cfg|
78
+ if url = ENV["DATABASE_URL"]
79
+ cfg[@env] ||= {}
80
+ cfg[@env]["url"] ||= url
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ # Returns the connection currently associated with the class. This can
87
+ # also be used to "borrow" the connection to do database work unrelated
88
+ # to any of the specific Active Records.
89
+ def connection
90
+ retrieve_connection
91
+ end
92
+
93
+ attr_writer :connection_specification_name
94
+
95
+ # Return the specification name from the current class or its parent.
96
+ def connection_specification_name
97
+ if !defined?(@connection_specification_name) || @connection_specification_name.nil?
98
+ return self == Base ? "primary" : superclass.connection_specification_name
99
+ end
100
+ @connection_specification_name
101
+ end
102
+
103
+ # Returns the configuration of the associated connection as a hash:
104
+ #
105
+ # ActiveRecord::Base.connection_config
106
+ # # => {pool: 5, timeout: 5000, database: "db/development.sqlite3", adapter: "sqlite3"}
107
+ #
108
+ # Please use only for reading.
109
+ def connection_config
110
+ connection_pool.spec.config
111
+ end
112
+
113
+ def connection_pool
114
+ connection_handler.retrieve_connection_pool(connection_specification_name) || raise(ConnectionNotEstablished)
115
+ end
116
+
117
+ def retrieve_connection
118
+ connection_handler.retrieve_connection(connection_specification_name)
119
+ end
120
+
121
+ # Returns +true+ if Active Record is connected.
122
+ def connected?
123
+ connection_handler.connected?(connection_specification_name)
124
+ end
125
+
126
+ def remove_connection(name = nil)
127
+ name ||= @connection_specification_name if defined?(@connection_specification_name)
128
+ # if removing a connection that has a pool, we reset the
129
+ # connection_specification_name so it will use the parent
130
+ # pool.
131
+ if connection_handler.retrieve_connection_pool(name)
132
+ self.connection_specification_name = nil
133
+ end
134
+
135
+ connection_handler.remove_connection(name)
136
+ end
137
+
138
+ def clear_cache! # :nodoc:
139
+ connection.schema_cache.clear!
140
+ end
141
+
142
+ delegate :clear_active_connections!, :clear_reloadable_connections!,
143
+ :clear_all_connections!, :flush_idle_connections!, to: :connection_handler
144
+ end
145
+ end
@@ -0,0 +1,559 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/hash/indifferent_access"
4
+ require "active_support/core_ext/string/filters"
5
+ require "concurrent/map"
6
+
7
+ module ActiveRecord
8
+ module Core
9
+ extend ActiveSupport::Concern
10
+
11
+ included do
12
+ ##
13
+ # :singleton-method:
14
+ #
15
+ # Accepts a logger conforming to the interface of Log4r which is then
16
+ # passed on to any new database connections made and which can be
17
+ # retrieved on both a class and instance level by calling +logger+.
18
+ mattr_accessor :logger, instance_writer: false
19
+
20
+ ##
21
+ # :singleton-method:
22
+ #
23
+ # Specifies if the methods calling database queries should be logged below
24
+ # their relevant queries. Defaults to false.
25
+ mattr_accessor :verbose_query_logs, instance_writer: false, default: false
26
+
27
+ ##
28
+ # Contains the database configuration - as is typically stored in config/database.yml -
29
+ # as a Hash.
30
+ #
31
+ # For example, the following database.yml...
32
+ #
33
+ # development:
34
+ # adapter: sqlite3
35
+ # database: db/development.sqlite3
36
+ #
37
+ # production:
38
+ # adapter: sqlite3
39
+ # database: db/production.sqlite3
40
+ #
41
+ # ...would result in ActiveRecord::Base.configurations to look like this:
42
+ #
43
+ # {
44
+ # 'development' => {
45
+ # 'adapter' => 'sqlite3',
46
+ # 'database' => 'db/development.sqlite3'
47
+ # },
48
+ # 'production' => {
49
+ # 'adapter' => 'sqlite3',
50
+ # 'database' => 'db/production.sqlite3'
51
+ # }
52
+ # }
53
+ def self.configurations=(config)
54
+ @@configurations = ActiveRecord::ConnectionHandling::MergeAndResolveDefaultUrlConfig.new(config).resolve
55
+ end
56
+ self.configurations = {}
57
+
58
+ # Returns fully resolved configurations hash
59
+ def self.configurations
60
+ @@configurations
61
+ end
62
+
63
+ ##
64
+ # :singleton-method:
65
+ # Determines whether to use Time.utc (using :utc) or Time.local (using :local) when pulling
66
+ # dates and times from the database. This is set to :utc by default.
67
+ mattr_accessor :default_timezone, instance_writer: false, default: :utc
68
+
69
+ ##
70
+ # :singleton-method:
71
+ # Specifies the format to use when dumping the database schema with Rails'
72
+ # Rakefile. If :sql, the schema is dumped as (potentially database-
73
+ # specific) SQL statements. If :ruby, the schema is dumped as an
74
+ # ActiveRecord::Schema file which can be loaded into any database that
75
+ # supports migrations. Use :ruby if you want to have different database
76
+ # adapters for, e.g., your development and test environments.
77
+ mattr_accessor :schema_format, instance_writer: false, default: :ruby
78
+
79
+ ##
80
+ # :singleton-method:
81
+ # Specifies if an error should be raised if the query has an order being
82
+ # ignored when doing batch queries. Useful in applications where the
83
+ # scope being ignored is error-worthy, rather than a warning.
84
+ mattr_accessor :error_on_ignored_order, instance_writer: false, default: false
85
+
86
+ # :singleton-method:
87
+ # Specify the behavior for unsafe raw query methods. Values are as follows
88
+ # deprecated - Warnings are logged when unsafe raw SQL is passed to
89
+ # query methods.
90
+ # disabled - Unsafe raw SQL passed to query methods results in
91
+ # UnknownAttributeReference exception.
92
+ mattr_accessor :allow_unsafe_raw_sql, instance_writer: false, default: :deprecated
93
+
94
+ ##
95
+ # :singleton-method:
96
+ # Specify whether or not to use timestamps for migration versions
97
+ mattr_accessor :timestamped_migrations, instance_writer: false, default: true
98
+
99
+ ##
100
+ # :singleton-method:
101
+ # Specify whether schema dump should happen at the end of the
102
+ # db:migrate rake task. This is true by default, which is useful for the
103
+ # development environment. This should ideally be false in the production
104
+ # environment where dumping schema is rarely needed.
105
+ mattr_accessor :dump_schema_after_migration, instance_writer: false, default: true
106
+
107
+ ##
108
+ # :singleton-method:
109
+ # Specifies which database schemas to dump when calling db:structure:dump.
110
+ # If the value is :schema_search_path (the default), any schemas listed in
111
+ # schema_search_path are dumped. Use :all to dump all schemas regardless
112
+ # of schema_search_path, or a string of comma separated schemas for a
113
+ # custom list.
114
+ mattr_accessor :dump_schemas, instance_writer: false, default: :schema_search_path
115
+
116
+ ##
117
+ # :singleton-method:
118
+ # Specify a threshold for the size of query result sets. If the number of
119
+ # records in the set exceeds the threshold, a warning is logged. This can
120
+ # be used to identify queries which load thousands of records and
121
+ # potentially cause memory bloat.
122
+ mattr_accessor :warn_on_records_fetched_greater_than, instance_writer: false
123
+
124
+ mattr_accessor :maintain_test_schema, instance_accessor: false
125
+
126
+ mattr_accessor :belongs_to_required_by_default, instance_accessor: false
127
+
128
+ class_attribute :default_connection_handler, instance_writer: false
129
+
130
+ def self.connection_handler
131
+ ActiveRecord::RuntimeRegistry.connection_handler || default_connection_handler
132
+ end
133
+
134
+ def self.connection_handler=(handler)
135
+ ActiveRecord::RuntimeRegistry.connection_handler = handler
136
+ end
137
+
138
+ self.default_connection_handler = ConnectionAdapters::ConnectionHandler.new
139
+ end
140
+
141
+ module ClassMethods # :nodoc:
142
+ def allocate
143
+ define_attribute_methods
144
+ super
145
+ end
146
+
147
+ def initialize_find_by_cache # :nodoc:
148
+ @find_by_statement_cache = { true => Concurrent::Map.new, false => Concurrent::Map.new }
149
+ end
150
+
151
+ def inherited(child_class) # :nodoc:
152
+ # initialize cache at class definition for thread safety
153
+ child_class.initialize_find_by_cache
154
+ super
155
+ end
156
+
157
+ def find(*ids) # :nodoc:
158
+ # We don't have cache keys for this stuff yet
159
+ return super unless ids.length == 1
160
+ return super if block_given? ||
161
+ primary_key.nil? ||
162
+ scope_attributes? ||
163
+ columns_hash.include?(inheritance_column)
164
+
165
+ id = ids.first
166
+
167
+ return super if StatementCache.unsupported_value?(id)
168
+
169
+ key = primary_key
170
+
171
+ statement = cached_find_by_statement(key) { |params|
172
+ where(key => params.bind).limit(1)
173
+ }
174
+
175
+ record = statement.execute([id], connection).first
176
+ unless record
177
+ raise RecordNotFound.new("Couldn't find #{name} with '#{primary_key}'=#{id}",
178
+ name, primary_key, id)
179
+ end
180
+ record
181
+ rescue ::RangeError
182
+ raise RecordNotFound.new("Couldn't find #{name} with an out of range value for '#{primary_key}'",
183
+ name, primary_key)
184
+ end
185
+
186
+ def find_by(*args) # :nodoc:
187
+ return super if scope_attributes? || reflect_on_all_aggregations.any? ||
188
+ columns_hash.key?(inheritance_column) && base_class != self
189
+
190
+ hash = args.first
191
+
192
+ return super if !(Hash === hash) || hash.values.any? { |v|
193
+ StatementCache.unsupported_value?(v)
194
+ }
195
+
196
+ # We can't cache Post.find_by(author: david) ...yet
197
+ return super unless hash.keys.all? { |k| columns_hash.has_key?(k.to_s) }
198
+
199
+ keys = hash.keys
200
+
201
+ statement = cached_find_by_statement(keys) { |params|
202
+ wheres = keys.each_with_object({}) { |param, o|
203
+ o[param] = params.bind
204
+ }
205
+ where(wheres).limit(1)
206
+ }
207
+ begin
208
+ statement.execute(hash.values, connection).first
209
+ rescue TypeError
210
+ raise ActiveRecord::StatementInvalid
211
+ rescue ::RangeError
212
+ nil
213
+ end
214
+ end
215
+
216
+ def find_by!(*args) # :nodoc:
217
+ find_by(*args) || raise(RecordNotFound.new("Couldn't find #{name}", name))
218
+ end
219
+
220
+ def initialize_generated_modules # :nodoc:
221
+ generated_association_methods
222
+ end
223
+
224
+ def generated_association_methods
225
+ @generated_association_methods ||= begin
226
+ mod = const_set(:GeneratedAssociationMethods, Module.new)
227
+ private_constant :GeneratedAssociationMethods
228
+ include mod
229
+
230
+ mod
231
+ end
232
+ end
233
+
234
+ # Returns a string like 'Post(id:integer, title:string, body:text)'
235
+ def inspect
236
+ if self == Base
237
+ super
238
+ elsif abstract_class?
239
+ "#{super}(abstract)"
240
+ elsif !connected?
241
+ "#{super} (call '#{super}.connection' to establish a connection)"
242
+ elsif table_exists?
243
+ attr_list = attribute_types.map { |name, type| "#{name}: #{type.type}" } * ", "
244
+ "#{super}(#{attr_list})"
245
+ else
246
+ "#{super}(Table doesn't exist)"
247
+ end
248
+ end
249
+
250
+ # Overwrite the default class equality method to provide support for decorated models.
251
+ def ===(object)
252
+ object.is_a?(self)
253
+ end
254
+
255
+ # Returns an instance of <tt>Arel::Table</tt> loaded with the current table name.
256
+ #
257
+ # class Post < ActiveRecord::Base
258
+ # scope :published_and_commented, -> { published.and(arel_table[:comments_count].gt(0)) }
259
+ # end
260
+ def arel_table # :nodoc:
261
+ @arel_table ||= Arel::Table.new(table_name, type_caster: type_caster)
262
+ end
263
+
264
+ def arel_attribute(name, table = arel_table) # :nodoc:
265
+ name = attribute_alias(name) if attribute_alias?(name)
266
+ table[name]
267
+ end
268
+
269
+ def predicate_builder # :nodoc:
270
+ @predicate_builder ||= PredicateBuilder.new(table_metadata)
271
+ end
272
+
273
+ def type_caster # :nodoc:
274
+ TypeCaster::Map.new(self)
275
+ end
276
+
277
+ private
278
+
279
+ def cached_find_by_statement(key, &block)
280
+ cache = @find_by_statement_cache[connection.prepared_statements]
281
+ cache.compute_if_absent(key) { StatementCache.create(connection, &block) }
282
+ end
283
+
284
+ def relation
285
+ relation = Relation.create(self)
286
+
287
+ if finder_needs_type_condition? && !ignore_default_scope?
288
+ relation.where!(type_condition)
289
+ relation.create_with!(inheritance_column.to_s => sti_name)
290
+ else
291
+ relation
292
+ end
293
+ end
294
+
295
+ def table_metadata
296
+ TableMetadata.new(self, arel_table)
297
+ end
298
+ end
299
+
300
+ # New objects can be instantiated as either empty (pass no construction parameter) or pre-set with
301
+ # attributes but not yet saved (pass a hash with key names matching the associated table column names).
302
+ # In both instances, valid attribute keys are determined by the column names of the associated table --
303
+ # hence you can't have attributes that aren't part of the table columns.
304
+ #
305
+ # ==== Example:
306
+ # # Instantiates a single new object
307
+ # User.new(first_name: 'Jamie')
308
+ def initialize(attributes = nil)
309
+ self.class.define_attribute_methods
310
+ @attributes = self.class._default_attributes.deep_dup
311
+
312
+ init_internals
313
+ initialize_internals_callback
314
+
315
+ assign_attributes(attributes) if attributes
316
+
317
+ yield self if block_given?
318
+ _run_initialize_callbacks
319
+ end
320
+
321
+ # Initialize an empty model object from +coder+. +coder+ should be
322
+ # the result of previously encoding an Active Record model, using
323
+ # #encode_with.
324
+ #
325
+ # class Post < ActiveRecord::Base
326
+ # end
327
+ #
328
+ # old_post = Post.new(title: "hello world")
329
+ # coder = {}
330
+ # old_post.encode_with(coder)
331
+ #
332
+ # post = Post.allocate
333
+ # post.init_with(coder)
334
+ # post.title # => 'hello world'
335
+ def init_with(coder)
336
+ coder = LegacyYamlAdapter.convert(self.class, coder)
337
+ @attributes = self.class.yaml_encoder.decode(coder)
338
+
339
+ init_internals
340
+
341
+ @new_record = coder["new_record"]
342
+
343
+ self.class.define_attribute_methods
344
+
345
+ yield self if block_given?
346
+
347
+ _run_find_callbacks
348
+ _run_initialize_callbacks
349
+
350
+ self
351
+ end
352
+
353
+ ##
354
+ # :method: clone
355
+ # Identical to Ruby's clone method. This is a "shallow" copy. Be warned that your attributes are not copied.
356
+ # That means that modifying attributes of the clone will modify the original, since they will both point to the
357
+ # same attributes hash. If you need a copy of your attributes hash, please use the #dup method.
358
+ #
359
+ # user = User.first
360
+ # new_user = user.clone
361
+ # user.name # => "Bob"
362
+ # new_user.name = "Joe"
363
+ # user.name # => "Joe"
364
+ #
365
+ # user.object_id == new_user.object_id # => false
366
+ # user.name.object_id == new_user.name.object_id # => true
367
+ #
368
+ # user.name.object_id == user.dup.name.object_id # => false
369
+
370
+ ##
371
+ # :method: dup
372
+ # Duped objects have no id assigned and are treated as new records. Note
373
+ # that this is a "shallow" copy as it copies the object's attributes
374
+ # only, not its associations. The extent of a "deep" copy is application
375
+ # specific and is therefore left to the application to implement according
376
+ # to its need.
377
+ # The dup method does not preserve the timestamps (created|updated)_(at|on).
378
+
379
+ ##
380
+ def initialize_dup(other) # :nodoc:
381
+ @attributes = @attributes.deep_dup
382
+ @attributes.reset(self.class.primary_key)
383
+
384
+ _run_initialize_callbacks
385
+
386
+ @new_record = true
387
+ @destroyed = false
388
+ @_start_transaction_state = {}
389
+ @transaction_state = nil
390
+
391
+ super
392
+ end
393
+
394
+ # Populate +coder+ with attributes about this record that should be
395
+ # serialized. The structure of +coder+ defined in this method is
396
+ # guaranteed to match the structure of +coder+ passed to the #init_with
397
+ # method.
398
+ #
399
+ # Example:
400
+ #
401
+ # class Post < ActiveRecord::Base
402
+ # end
403
+ # coder = {}
404
+ # Post.new.encode_with(coder)
405
+ # coder # => {"attributes" => {"id" => nil, ... }}
406
+ def encode_with(coder)
407
+ self.class.yaml_encoder.encode(@attributes, coder)
408
+ coder["new_record"] = new_record?
409
+ coder["active_record_yaml_version"] = 2
410
+ end
411
+
412
+ # Returns true if +comparison_object+ is the same exact object, or +comparison_object+
413
+ # is of the same type and +self+ has an ID and it is equal to +comparison_object.id+.
414
+ #
415
+ # Note that new records are different from any other record by definition, unless the
416
+ # other record is the receiver itself. Besides, if you fetch existing records with
417
+ # +select+ and leave the ID out, you're on your own, this predicate will return false.
418
+ #
419
+ # Note also that destroying a record preserves its ID in the model instance, so deleted
420
+ # models are still comparable.
421
+ def ==(comparison_object)
422
+ super ||
423
+ comparison_object.instance_of?(self.class) &&
424
+ !id.nil? &&
425
+ comparison_object.id == id
426
+ end
427
+ alias :eql? :==
428
+
429
+ # Delegates to id in order to allow two records of the same type and id to work with something like:
430
+ # [ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
431
+ def hash
432
+ if id
433
+ self.class.hash ^ id.hash
434
+ else
435
+ super
436
+ end
437
+ end
438
+
439
+ # Clone and freeze the attributes hash such that associations are still
440
+ # accessible, even on destroyed records, but cloned models will not be
441
+ # frozen.
442
+ def freeze
443
+ @attributes = @attributes.clone.freeze
444
+ self
445
+ end
446
+
447
+ # Returns +true+ if the attributes hash has been frozen.
448
+ def frozen?
449
+ @attributes.frozen?
450
+ end
451
+
452
+ # Allows sort on objects
453
+ def <=>(other_object)
454
+ if other_object.is_a?(self.class)
455
+ to_key <=> other_object.to_key
456
+ else
457
+ super
458
+ end
459
+ end
460
+
461
+ # Returns +true+ if the record is read only. Records loaded through joins with piggy-back
462
+ # attributes will be marked as read only since they cannot be saved.
463
+ def readonly?
464
+ @readonly
465
+ end
466
+
467
+ # Marks this record as read only.
468
+ def readonly!
469
+ @readonly = true
470
+ end
471
+
472
+ def connection_handler
473
+ self.class.connection_handler
474
+ end
475
+
476
+ # Returns the contents of the record as a nicely formatted string.
477
+ def inspect
478
+ # We check defined?(@attributes) not to issue warnings if the object is
479
+ # allocated but not initialized.
480
+ inspection = if defined?(@attributes) && @attributes
481
+ self.class.attribute_names.collect do |name|
482
+ if has_attribute?(name)
483
+ "#{name}: #{attribute_for_inspect(name)}"
484
+ end
485
+ end.compact.join(", ")
486
+ else
487
+ "not initialized"
488
+ end
489
+
490
+ "#<#{self.class} #{inspection}>"
491
+ end
492
+
493
+ # Takes a PP and prettily prints this record to it, allowing you to get a nice result from <tt>pp record</tt>
494
+ # when pp is required.
495
+ def pretty_print(pp)
496
+ return super if custom_inspect_method_defined?
497
+ pp.object_address_group(self) do
498
+ if defined?(@attributes) && @attributes
499
+ column_names = self.class.column_names.select { |name| has_attribute?(name) || new_record? }
500
+ pp.seplist(column_names, proc { pp.text "," }) do |column_name|
501
+ column_value = read_attribute(column_name)
502
+ pp.breakable " "
503
+ pp.group(1) do
504
+ pp.text column_name
505
+ pp.text ":"
506
+ pp.breakable
507
+ pp.pp column_value
508
+ end
509
+ end
510
+ else
511
+ pp.breakable " "
512
+ pp.text "not initialized"
513
+ end
514
+ end
515
+ end
516
+
517
+ # Returns a hash of the given methods with their names as keys and returned values as values.
518
+ def slice(*methods)
519
+ Hash[methods.flatten.map! { |method| [method, public_send(method)] }].with_indifferent_access
520
+ end
521
+
522
+ private
523
+
524
+ # +Array#flatten+ will call +#to_ary+ (recursively) on each of the elements of
525
+ # the array, and then rescues from the possible +NoMethodError+. If those elements are
526
+ # +ActiveRecord::Base+'s, then this triggers the various +method_missing+'s that we have,
527
+ # which significantly impacts upon performance.
528
+ #
529
+ # So we can avoid the +method_missing+ hit by explicitly defining +#to_ary+ as +nil+ here.
530
+ #
531
+ # See also https://tenderlovemaking.com/2011/06/28/til-its-ok-to-return-nil-from-to_ary.html
532
+ def to_ary
533
+ nil
534
+ end
535
+
536
+ def init_internals
537
+ @readonly = false
538
+ @destroyed = false
539
+ @marked_for_destruction = false
540
+ @destroyed_by_association = nil
541
+ @new_record = true
542
+ @_start_transaction_state = {}
543
+ @transaction_state = nil
544
+ end
545
+
546
+ def initialize_internals_callback
547
+ end
548
+
549
+ def thaw
550
+ if frozen?
551
+ @attributes = @attributes.dup
552
+ end
553
+ end
554
+
555
+ def custom_inspect_method_defined?
556
+ self.class.instance_method(:inspect).owner != ActiveRecord::Base.instance_method(:inspect).owner
557
+ end
558
+ end
559
+ end