activerecord 6.1.7 → 7.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (311) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +2030 -1020
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +18 -18
  5. data/lib/active_record/aggregations.rb +17 -14
  6. data/lib/active_record/association_relation.rb +1 -11
  7. data/lib/active_record/associations/association.rb +51 -19
  8. data/lib/active_record/associations/association_scope.rb +17 -12
  9. data/lib/active_record/associations/belongs_to_association.rb +28 -9
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  11. data/lib/active_record/associations/builder/association.rb +11 -5
  12. data/lib/active_record/associations/builder/belongs_to.rb +40 -14
  13. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  14. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +1 -5
  15. data/lib/active_record/associations/builder/has_many.rb +3 -2
  16. data/lib/active_record/associations/builder/has_one.rb +2 -1
  17. data/lib/active_record/associations/builder/singular_association.rb +6 -2
  18. data/lib/active_record/associations/collection_association.rb +39 -35
  19. data/lib/active_record/associations/collection_proxy.rb +30 -15
  20. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  21. data/lib/active_record/associations/foreign_association.rb +10 -3
  22. data/lib/active_record/associations/has_many_association.rb +28 -18
  23. data/lib/active_record/associations/has_many_through_association.rb +12 -7
  24. data/lib/active_record/associations/has_one_association.rb +20 -10
  25. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  26. data/lib/active_record/associations/join_dependency/join_association.rb +3 -2
  27. data/lib/active_record/associations/join_dependency.rb +28 -20
  28. data/lib/active_record/associations/preloader/association.rb +210 -52
  29. data/lib/active_record/associations/preloader/batch.rb +48 -0
  30. data/lib/active_record/associations/preloader/branch.rb +147 -0
  31. data/lib/active_record/associations/preloader/through_association.rb +50 -14
  32. data/lib/active_record/associations/preloader.rb +50 -121
  33. data/lib/active_record/associations/singular_association.rb +9 -3
  34. data/lib/active_record/associations/through_association.rb +25 -14
  35. data/lib/active_record/associations.rb +446 -306
  36. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  37. data/lib/active_record/attribute_assignment.rb +1 -3
  38. data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
  39. data/lib/active_record/attribute_methods/dirty.rb +73 -22
  40. data/lib/active_record/attribute_methods/primary_key.rb +78 -26
  41. data/lib/active_record/attribute_methods/query.rb +31 -19
  42. data/lib/active_record/attribute_methods/read.rb +27 -12
  43. data/lib/active_record/attribute_methods/serialization.rb +194 -37
  44. data/lib/active_record/attribute_methods/time_zone_conversion.rb +8 -3
  45. data/lib/active_record/attribute_methods/write.rb +12 -15
  46. data/lib/active_record/attribute_methods.rb +161 -40
  47. data/lib/active_record/attributes.rb +27 -38
  48. data/lib/active_record/autosave_association.rb +65 -31
  49. data/lib/active_record/base.rb +25 -2
  50. data/lib/active_record/callbacks.rb +18 -34
  51. data/lib/active_record/coders/column_serializer.rb +61 -0
  52. data/lib/active_record/coders/json.rb +1 -1
  53. data/lib/active_record/coders/yaml_column.rb +70 -46
  54. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +367 -0
  55. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +78 -0
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +113 -597
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +172 -50
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +78 -27
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +87 -73
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +367 -141
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +281 -59
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +631 -150
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +317 -164
  70. data/lib/active_record/connection_adapters/column.rb +13 -0
  71. data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
  72. data/lib/active_record/connection_adapters/mysql/database_statements.rb +25 -134
  73. data/lib/active_record/connection_adapters/mysql/quoting.rb +56 -25
  74. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
  76. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
  77. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +39 -14
  78. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +151 -0
  79. data/lib/active_record/connection_adapters/mysql2_adapter.rb +112 -55
  80. data/lib/active_record/connection_adapters/pool_config.rb +20 -11
  81. data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +89 -52
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  89. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
  90. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
  91. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  94. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/quoting.rb +89 -56
  96. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
  97. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +153 -3
  99. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
  100. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +397 -75
  101. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
  102. data/lib/active_record/connection_adapters/postgresql_adapter.rb +508 -246
  103. data/lib/active_record/connection_adapters/schema_cache.rb +319 -90
  104. data/lib/active_record/connection_adapters/sqlite3/column.rb +49 -0
  105. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +72 -53
  106. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +37 -21
  107. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +7 -0
  108. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -22
  109. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +296 -104
  110. data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
  111. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
  112. data/lib/active_record/connection_adapters/trilogy_adapter.rb +258 -0
  113. data/lib/active_record/connection_adapters.rb +9 -6
  114. data/lib/active_record/connection_handling.rb +108 -137
  115. data/lib/active_record/core.rb +242 -233
  116. data/lib/active_record/counter_cache.rb +52 -27
  117. data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -2
  118. data/lib/active_record/database_configurations/database_config.rb +21 -12
  119. data/lib/active_record/database_configurations/hash_config.rb +88 -16
  120. data/lib/active_record/database_configurations/url_config.rb +18 -12
  121. data/lib/active_record/database_configurations.rb +95 -59
  122. data/lib/active_record/delegated_type.rb +66 -20
  123. data/lib/active_record/deprecator.rb +7 -0
  124. data/lib/active_record/destroy_association_async_job.rb +4 -2
  125. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  126. data/lib/active_record/dynamic_matchers.rb +1 -1
  127. data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
  128. data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
  129. data/lib/active_record/encryption/cipher.rb +53 -0
  130. data/lib/active_record/encryption/config.rb +68 -0
  131. data/lib/active_record/encryption/configurable.rb +60 -0
  132. data/lib/active_record/encryption/context.rb +42 -0
  133. data/lib/active_record/encryption/contexts.rb +76 -0
  134. data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
  135. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  136. data/lib/active_record/encryption/encryptable_record.rb +230 -0
  137. data/lib/active_record/encryption/encrypted_attribute_type.rb +155 -0
  138. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  139. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  140. data/lib/active_record/encryption/encryptor.rb +155 -0
  141. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  142. data/lib/active_record/encryption/errors.rb +15 -0
  143. data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
  144. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  145. data/lib/active_record/encryption/key.rb +28 -0
  146. data/lib/active_record/encryption/key_generator.rb +53 -0
  147. data/lib/active_record/encryption/key_provider.rb +46 -0
  148. data/lib/active_record/encryption/message.rb +33 -0
  149. data/lib/active_record/encryption/message_serializer.rb +92 -0
  150. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  151. data/lib/active_record/encryption/properties.rb +76 -0
  152. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  153. data/lib/active_record/encryption/scheme.rb +100 -0
  154. data/lib/active_record/encryption.rb +58 -0
  155. data/lib/active_record/enum.rb +154 -63
  156. data/lib/active_record/errors.rb +172 -15
  157. data/lib/active_record/explain.rb +23 -3
  158. data/lib/active_record/explain_registry.rb +11 -6
  159. data/lib/active_record/explain_subscriber.rb +1 -1
  160. data/lib/active_record/fixture_set/file.rb +15 -1
  161. data/lib/active_record/fixture_set/model_metadata.rb +14 -4
  162. data/lib/active_record/fixture_set/render_context.rb +2 -0
  163. data/lib/active_record/fixture_set/table_row.rb +70 -14
  164. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  165. data/lib/active_record/fixtures.rb +147 -86
  166. data/lib/active_record/future_result.rb +174 -0
  167. data/lib/active_record/gem_version.rb +3 -3
  168. data/lib/active_record/inheritance.rb +81 -29
  169. data/lib/active_record/insert_all.rb +135 -22
  170. data/lib/active_record/integration.rb +11 -10
  171. data/lib/active_record/internal_metadata.rb +119 -33
  172. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  173. data/lib/active_record/locking/optimistic.rb +37 -22
  174. data/lib/active_record/locking/pessimistic.rb +15 -6
  175. data/lib/active_record/log_subscriber.rb +52 -19
  176. data/lib/active_record/marshalling.rb +59 -0
  177. data/lib/active_record/message_pack.rb +124 -0
  178. data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
  179. data/lib/active_record/middleware/database_selector.rb +23 -13
  180. data/lib/active_record/middleware/shard_selector.rb +62 -0
  181. data/lib/active_record/migration/command_recorder.rb +112 -14
  182. data/lib/active_record/migration/compatibility.rb +233 -46
  183. data/lib/active_record/migration/default_strategy.rb +23 -0
  184. data/lib/active_record/migration/execution_strategy.rb +19 -0
  185. data/lib/active_record/migration/join_table.rb +1 -1
  186. data/lib/active_record/migration/pending_migration_connection.rb +21 -0
  187. data/lib/active_record/migration.rb +361 -173
  188. data/lib/active_record/model_schema.rb +125 -101
  189. data/lib/active_record/nested_attributes.rb +50 -20
  190. data/lib/active_record/no_touching.rb +3 -3
  191. data/lib/active_record/normalization.rb +167 -0
  192. data/lib/active_record/persistence.rb +409 -88
  193. data/lib/active_record/promise.rb +84 -0
  194. data/lib/active_record/query_cache.rb +4 -22
  195. data/lib/active_record/query_logs.rb +174 -0
  196. data/lib/active_record/query_logs_formatter.rb +41 -0
  197. data/lib/active_record/querying.rb +29 -6
  198. data/lib/active_record/railtie.rb +220 -44
  199. data/lib/active_record/railties/controller_runtime.rb +15 -10
  200. data/lib/active_record/railties/databases.rake +188 -252
  201. data/lib/active_record/railties/job_runtime.rb +23 -0
  202. data/lib/active_record/readonly_attributes.rb +41 -3
  203. data/lib/active_record/reflection.rb +248 -81
  204. data/lib/active_record/relation/batches/batch_enumerator.rb +23 -7
  205. data/lib/active_record/relation/batches.rb +192 -63
  206. data/lib/active_record/relation/calculations.rb +246 -90
  207. data/lib/active_record/relation/delegation.rb +28 -14
  208. data/lib/active_record/relation/finder_methods.rb +108 -51
  209. data/lib/active_record/relation/merger.rb +22 -13
  210. data/lib/active_record/relation/predicate_builder/association_query_value.rb +31 -3
  211. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
  212. data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
  213. data/lib/active_record/relation/predicate_builder.rb +27 -20
  214. data/lib/active_record/relation/query_attribute.rb +30 -12
  215. data/lib/active_record/relation/query_methods.rb +670 -129
  216. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  217. data/lib/active_record/relation/spawn_methods.rb +20 -3
  218. data/lib/active_record/relation/where_clause.rb +10 -19
  219. data/lib/active_record/relation.rb +287 -120
  220. data/lib/active_record/result.rb +37 -11
  221. data/lib/active_record/runtime_registry.rb +32 -13
  222. data/lib/active_record/sanitization.rb +65 -20
  223. data/lib/active_record/schema.rb +36 -22
  224. data/lib/active_record/schema_dumper.rb +73 -24
  225. data/lib/active_record/schema_migration.rb +68 -33
  226. data/lib/active_record/scoping/default.rb +72 -15
  227. data/lib/active_record/scoping/named.rb +5 -13
  228. data/lib/active_record/scoping.rb +65 -34
  229. data/lib/active_record/secure_password.rb +60 -0
  230. data/lib/active_record/secure_token.rb +21 -3
  231. data/lib/active_record/serialization.rb +6 -1
  232. data/lib/active_record/signed_id.rb +10 -8
  233. data/lib/active_record/store.rb +10 -10
  234. data/lib/active_record/suppressor.rb +13 -15
  235. data/lib/active_record/table_metadata.rb +16 -3
  236. data/lib/active_record/tasks/database_tasks.rb +251 -140
  237. data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
  238. data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
  239. data/lib/active_record/tasks/sqlite_database_tasks.rb +15 -7
  240. data/lib/active_record/test_databases.rb +1 -1
  241. data/lib/active_record/test_fixtures.rb +117 -96
  242. data/lib/active_record/timestamp.rb +32 -19
  243. data/lib/active_record/token_for.rb +113 -0
  244. data/lib/active_record/touch_later.rb +11 -6
  245. data/lib/active_record/transactions.rb +48 -27
  246. data/lib/active_record/translation.rb +3 -3
  247. data/lib/active_record/type/adapter_specific_registry.rb +32 -14
  248. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  249. data/lib/active_record/type/internal/timezone.rb +7 -2
  250. data/lib/active_record/type/serialized.rb +9 -5
  251. data/lib/active_record/type/time.rb +4 -0
  252. data/lib/active_record/type/type_map.rb +17 -20
  253. data/lib/active_record/type.rb +1 -2
  254. data/lib/active_record/validations/absence.rb +1 -1
  255. data/lib/active_record/validations/associated.rb +4 -4
  256. data/lib/active_record/validations/numericality.rb +5 -4
  257. data/lib/active_record/validations/presence.rb +5 -28
  258. data/lib/active_record/validations/uniqueness.rb +51 -6
  259. data/lib/active_record/validations.rb +8 -4
  260. data/lib/active_record/version.rb +1 -1
  261. data/lib/active_record.rb +335 -32
  262. data/lib/arel/attributes/attribute.rb +0 -8
  263. data/lib/arel/crud.rb +28 -22
  264. data/lib/arel/delete_manager.rb +18 -4
  265. data/lib/arel/errors.rb +10 -0
  266. data/lib/arel/factory_methods.rb +4 -0
  267. data/lib/arel/filter_predications.rb +9 -0
  268. data/lib/arel/insert_manager.rb +2 -3
  269. data/lib/arel/nodes/and.rb +4 -0
  270. data/lib/arel/nodes/binary.rb +6 -1
  271. data/lib/arel/nodes/bound_sql_literal.rb +61 -0
  272. data/lib/arel/nodes/casted.rb +1 -1
  273. data/lib/arel/nodes/cte.rb +36 -0
  274. data/lib/arel/nodes/delete_statement.rb +12 -13
  275. data/lib/arel/nodes/filter.rb +10 -0
  276. data/lib/arel/nodes/fragments.rb +35 -0
  277. data/lib/arel/nodes/function.rb +1 -0
  278. data/lib/arel/nodes/homogeneous_in.rb +1 -9
  279. data/lib/arel/nodes/insert_statement.rb +2 -2
  280. data/lib/arel/nodes/leading_join.rb +8 -0
  281. data/lib/arel/nodes/node.rb +111 -2
  282. data/lib/arel/nodes/select_core.rb +2 -2
  283. data/lib/arel/nodes/select_statement.rb +2 -2
  284. data/lib/arel/nodes/sql_literal.rb +6 -0
  285. data/lib/arel/nodes/table_alias.rb +4 -0
  286. data/lib/arel/nodes/update_statement.rb +8 -3
  287. data/lib/arel/nodes.rb +5 -0
  288. data/lib/arel/predications.rb +13 -3
  289. data/lib/arel/select_manager.rb +10 -4
  290. data/lib/arel/table.rb +9 -6
  291. data/lib/arel/tree_manager.rb +5 -13
  292. data/lib/arel/update_manager.rb +18 -4
  293. data/lib/arel/visitors/dot.rb +80 -90
  294. data/lib/arel/visitors/mysql.rb +16 -3
  295. data/lib/arel/visitors/postgresql.rb +0 -10
  296. data/lib/arel/visitors/to_sql.rb +141 -20
  297. data/lib/arel/visitors/visitor.rb +2 -2
  298. data/lib/arel.rb +18 -3
  299. data/lib/rails/generators/active_record/application_record/USAGE +8 -0
  300. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  301. data/lib/rails/generators/active_record/migration.rb +3 -1
  302. data/lib/rails/generators/active_record/model/USAGE +113 -0
  303. data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
  304. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  305. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  306. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  307. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  308. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  309. metadata +96 -16
  310. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
  311. data/lib/active_record/null_relation.rb +0 -67
@@ -31,6 +31,40 @@ module Arel # :nodoc: all
31
31
  end
32
32
 
33
33
  private
34
+ def visit_Arel_Nodes_Function(o)
35
+ visit_edge o, "expressions"
36
+ visit_edge o, "distinct"
37
+ visit_edge o, "alias"
38
+ end
39
+
40
+ def visit_Arel_Nodes_Unary(o)
41
+ visit_edge o, "expr"
42
+ end
43
+
44
+ def visit_Arel_Nodes_Binary(o)
45
+ visit_edge o, "left"
46
+ visit_edge o, "right"
47
+ end
48
+
49
+ def visit_Arel_Nodes_UnaryOperation(o)
50
+ visit_edge o, "operator"
51
+ visit_edge o, "expr"
52
+ end
53
+
54
+ def visit_Arel_Nodes_InfixOperation(o)
55
+ visit_edge o, "operator"
56
+ visit_edge o, "left"
57
+ visit_edge o, "right"
58
+ end
59
+
60
+ def visit__regexp(o)
61
+ visit_edge o, "left"
62
+ visit_edge o, "right"
63
+ visit_edge o, "case_sensitive"
64
+ end
65
+ alias :visit_Arel_Nodes_Regexp :visit__regexp
66
+ alias :visit_Arel_Nodes_NotRegexp :visit__regexp
67
+
34
68
  def visit_Arel_Nodes_Ordering(o)
35
69
  visit_edge o, "expr"
36
70
  end
@@ -53,71 +87,29 @@ module Arel # :nodoc: all
53
87
  visit_edge o, "left"
54
88
  end
55
89
 
56
- def visit_Arel_Nodes_InnerJoin(o)
57
- visit_edge o, "left"
58
- visit_edge o, "right"
59
- end
60
- alias :visit_Arel_Nodes_FullOuterJoin :visit_Arel_Nodes_InnerJoin
61
- alias :visit_Arel_Nodes_OuterJoin :visit_Arel_Nodes_InnerJoin
62
- alias :visit_Arel_Nodes_RightOuterJoin :visit_Arel_Nodes_InnerJoin
63
-
64
- def visit_Arel_Nodes_DeleteStatement(o)
65
- visit_edge o, "relation"
66
- visit_edge o, "wheres"
67
- end
68
-
69
- def unary(o)
70
- visit_edge o, "expr"
71
- end
72
- alias :visit_Arel_Nodes_Group :unary
73
- alias :visit_Arel_Nodes_Cube :unary
74
- alias :visit_Arel_Nodes_RollUp :unary
75
- alias :visit_Arel_Nodes_GroupingSet :unary
76
- alias :visit_Arel_Nodes_GroupingElement :unary
77
- alias :visit_Arel_Nodes_Grouping :unary
78
- alias :visit_Arel_Nodes_Having :unary
79
- alias :visit_Arel_Nodes_Limit :unary
80
- alias :visit_Arel_Nodes_Not :unary
81
- alias :visit_Arel_Nodes_Offset :unary
82
- alias :visit_Arel_Nodes_On :unary
83
- alias :visit_Arel_Nodes_UnqualifiedColumn :unary
84
- alias :visit_Arel_Nodes_OptimizerHints :unary
85
- alias :visit_Arel_Nodes_Preceding :unary
86
- alias :visit_Arel_Nodes_Following :unary
87
- alias :visit_Arel_Nodes_Rows :unary
88
- alias :visit_Arel_Nodes_Range :unary
89
-
90
- def window(o)
90
+ def visit_Arel_Nodes_Window(o)
91
91
  visit_edge o, "partitions"
92
92
  visit_edge o, "orders"
93
93
  visit_edge o, "framing"
94
94
  end
95
- alias :visit_Arel_Nodes_Window :window
96
95
 
97
- def named_window(o)
96
+ def visit_Arel_Nodes_NamedWindow(o)
98
97
  visit_edge o, "partitions"
99
98
  visit_edge o, "orders"
100
99
  visit_edge o, "framing"
101
100
  visit_edge o, "name"
102
101
  end
103
- alias :visit_Arel_Nodes_NamedWindow :named_window
104
102
 
105
- def function(o)
106
- visit_edge o, "expressions"
107
- visit_edge o, "distinct"
108
- visit_edge o, "alias"
103
+ def visit__no_edges(o)
104
+ # intentionally left blank
109
105
  end
110
- alias :visit_Arel_Nodes_Exists :function
111
- alias :visit_Arel_Nodes_Min :function
112
- alias :visit_Arel_Nodes_Max :function
113
- alias :visit_Arel_Nodes_Avg :function
114
- alias :visit_Arel_Nodes_Sum :function
106
+ alias :visit_Arel_Nodes_CurrentRow :visit__no_edges
107
+ alias :visit_Arel_Nodes_Distinct :visit__no_edges
115
108
 
116
- def extract(o)
109
+ def visit_Arel_Nodes_Extract(o)
117
110
  visit_edge o, "expressions"
118
111
  visit_edge o, "alias"
119
112
  end
120
- alias :visit_Arel_Nodes_Extract :extract
121
113
 
122
114
  def visit_Arel_Nodes_NamedFunction(o)
123
115
  visit_edge o, "name"
@@ -130,13 +122,19 @@ module Arel # :nodoc: all
130
122
  visit_edge o, "relation"
131
123
  visit_edge o, "columns"
132
124
  visit_edge o, "values"
125
+ visit_edge o, "select"
133
126
  end
134
127
 
135
128
  def visit_Arel_Nodes_SelectCore(o)
136
129
  visit_edge o, "source"
137
130
  visit_edge o, "projections"
138
131
  visit_edge o, "wheres"
139
- visit_edge o, "windows"
132
+ visit_edge o, "windows"
133
+ visit_edge o, "groups"
134
+ visit_edge o, "comment"
135
+ visit_edge o, "havings"
136
+ visit_edge o, "set_quantifier"
137
+ visit_edge o, "optimizer_hints"
140
138
  end
141
139
 
142
140
  def visit_Arel_Nodes_SelectStatement(o)
@@ -144,12 +142,27 @@ module Arel # :nodoc: all
144
142
  visit_edge o, "limit"
145
143
  visit_edge o, "orders"
146
144
  visit_edge o, "offset"
145
+ visit_edge o, "lock"
146
+ visit_edge o, "with"
147
147
  end
148
148
 
149
149
  def visit_Arel_Nodes_UpdateStatement(o)
150
150
  visit_edge o, "relation"
151
151
  visit_edge o, "wheres"
152
152
  visit_edge o, "values"
153
+ visit_edge o, "orders"
154
+ visit_edge o, "limit"
155
+ visit_edge o, "offset"
156
+ visit_edge o, "key"
157
+ end
158
+
159
+ def visit_Arel_Nodes_DeleteStatement(o)
160
+ visit_edge o, "relation"
161
+ visit_edge o, "wheres"
162
+ visit_edge o, "orders"
163
+ visit_edge o, "limit"
164
+ visit_edge o, "offset"
165
+ visit_edge o, "key"
153
166
  end
154
167
 
155
168
  def visit_Arel_Table(o)
@@ -167,47 +180,18 @@ module Arel # :nodoc: all
167
180
  visit_edge o, "attribute"
168
181
  end
169
182
 
170
- def visit_Arel_Attribute(o)
183
+ def visit_Arel_Attributes_Attribute(o)
171
184
  visit_edge o, "relation"
172
185
  visit_edge o, "name"
173
186
  end
174
- alias :visit_Arel_Attributes_Integer :visit_Arel_Attribute
175
- alias :visit_Arel_Attributes_Float :visit_Arel_Attribute
176
- alias :visit_Arel_Attributes_String :visit_Arel_Attribute
177
- alias :visit_Arel_Attributes_Time :visit_Arel_Attribute
178
- alias :visit_Arel_Attributes_Boolean :visit_Arel_Attribute
179
- alias :visit_Arel_Attributes_Attribute :visit_Arel_Attribute
180
187
 
181
- def nary(o)
182
- o.children.each_with_index do |x, i|
183
- edge(i) { visit x }
188
+ def visit__children(o)
189
+ o.children.each_with_index do |child, i|
190
+ edge(i) { visit child }
184
191
  end
185
192
  end
186
- alias :visit_Arel_Nodes_And :nary
187
-
188
- def binary(o)
189
- visit_edge o, "left"
190
- visit_edge o, "right"
191
- end
192
- alias :visit_Arel_Nodes_As :binary
193
- alias :visit_Arel_Nodes_Assignment :binary
194
- alias :visit_Arel_Nodes_Between :binary
195
- alias :visit_Arel_Nodes_Concat :binary
196
- alias :visit_Arel_Nodes_DoesNotMatch :binary
197
- alias :visit_Arel_Nodes_Equality :binary
198
- alias :visit_Arel_Nodes_GreaterThan :binary
199
- alias :visit_Arel_Nodes_GreaterThanOrEqual :binary
200
- alias :visit_Arel_Nodes_In :binary
201
- alias :visit_Arel_Nodes_JoinSource :binary
202
- alias :visit_Arel_Nodes_LessThan :binary
203
- alias :visit_Arel_Nodes_LessThanOrEqual :binary
204
- alias :visit_Arel_Nodes_IsNotDistinctFrom :binary
205
- alias :visit_Arel_Nodes_IsDistinctFrom :binary
206
- alias :visit_Arel_Nodes_Matches :binary
207
- alias :visit_Arel_Nodes_NotEqual :binary
208
- alias :visit_Arel_Nodes_NotIn :binary
209
- alias :visit_Arel_Nodes_Or :binary
210
- alias :visit_Arel_Nodes_Over :binary
193
+ alias :visit_Arel_Nodes_And :visit__children
194
+ alias :visit_Arel_Nodes_With :visit__children
211
195
 
212
196
  def visit_String(o)
213
197
  @node_stack.last.fields << o
@@ -225,22 +209,22 @@ module Arel # :nodoc: all
225
209
  alias :visit_Arel_Nodes_SqlLiteral :visit_String
226
210
 
227
211
  def visit_Arel_Nodes_BindParam(o)
228
- edge("value") { visit o.value }
212
+ visit_edge(o, "value")
229
213
  end
230
214
 
231
215
  def visit_ActiveModel_Attribute(o)
232
- edge("value_before_type_cast") { visit o.value_before_type_cast }
216
+ visit_edge(o, "value_before_type_cast")
233
217
  end
234
218
 
235
219
  def visit_Hash(o)
236
220
  o.each_with_index do |pair, i|
237
- edge("pair_#{i}") { visit pair }
221
+ edge("pair_#{i}") { visit pair }
238
222
  end
239
223
  end
240
224
 
241
225
  def visit_Array(o)
242
- o.each_with_index do |x, i|
243
- edge(i) { visit x }
226
+ o.each_with_index do |member, i|
227
+ edge(i) { visit member }
244
228
  end
245
229
  end
246
230
  alias :visit_Set :visit_Array
@@ -249,6 +233,12 @@ module Arel # :nodoc: all
249
233
  visit_edge(o, "values")
250
234
  end
251
235
 
236
+ def visit_Arel_Nodes_Case(o)
237
+ visit_edge(o, "case")
238
+ visit_edge(o, "conditions")
239
+ visit_edge(o, "default")
240
+ end
241
+
252
242
  def visit_edge(o, method)
253
243
  edge(method) { visit o.send(method) }
254
244
  end
@@ -5,8 +5,9 @@ module Arel # :nodoc: all
5
5
  class MySQL < Arel::Visitors::ToSql
6
6
  private
7
7
  def visit_Arel_Nodes_Bin(o, collector)
8
- collector << "BINARY "
8
+ collector << "CAST("
9
9
  visit o.expr, collector
10
+ collector << " AS BINARY)"
10
11
  end
11
12
 
12
13
  def visit_Arel_Nodes_UnqualifiedColumn(o, collector)
@@ -58,11 +59,23 @@ module Arel # :nodoc: all
58
59
  infix_value o, collector, " NOT REGEXP "
59
60
  end
60
61
 
62
+ # no-op
63
+ def visit_Arel_Nodes_NullsFirst(o, collector)
64
+ visit o.expr, collector
65
+ end
66
+
67
+ def visit_Arel_Nodes_Cte(o, collector)
68
+ collector << quote_table_name(o.name)
69
+ collector << " AS "
70
+ visit o.relation, collector
71
+ end
72
+
61
73
  # In the simple case, MySQL allows us to place JOINs directly into the UPDATE
62
74
  # query. However, this does not allow for LIMIT, OFFSET and ORDER. To support
63
75
  # these, we must use a subquery.
64
76
  def prepare_update_statement(o)
65
- if o.offset || has_join_sources?(o) && has_limit_or_offset_or_orders?(o)
77
+ if o.offset || has_group_by_and_having?(o) ||
78
+ has_join_sources?(o) && has_limit_or_offset_or_orders?(o)
66
79
  super
67
80
  else
68
81
  o
@@ -70,7 +83,7 @@ module Arel # :nodoc: all
70
83
  end
71
84
  alias :prepare_delete_statement :prepare_update_statement
72
85
 
73
- # MySQL is too stupid to create a temporary table for use subquery, so we have
86
+ # MySQL doesn't automatically create a temporary table for use subquery, so we have
74
87
  # to give it some prompting in the form of a subsubquery.
75
88
  def build_subselect(key, o)
76
89
  subselect = super
@@ -78,16 +78,6 @@ module Arel # :nodoc: all
78
78
  visit o.right, collector
79
79
  end
80
80
 
81
- def visit_Arel_Nodes_NullsFirst(o, collector)
82
- visit o.expr, collector
83
- collector << " NULLS FIRST"
84
- end
85
-
86
- def visit_Arel_Nodes_NullsLast(o, collector)
87
- visit o.expr, collector
88
- collector << " NULLS LAST"
89
- end
90
-
91
81
  BIND_BLOCK = proc { |i| "$#{i}" }
92
82
  private_constant :BIND_BLOCK
93
83
 
@@ -103,7 +103,7 @@ module Arel # :nodoc: all
103
103
  row.each_with_index do |value, k|
104
104
  collector << ", " unless k == 0
105
105
  case value
106
- when Nodes::SqlLiteral, Nodes::BindParam
106
+ when Nodes::SqlLiteral, Nodes::BindParam, ActiveModel::Attribute
107
107
  collector = visit(value, collector)
108
108
  else
109
109
  collector << quote(value).to_s
@@ -135,6 +135,8 @@ module Arel # :nodoc: all
135
135
  visit_Arel_Nodes_SelectOptions(o, collector)
136
136
  end
137
137
 
138
+ # The Oracle enhanced adapter uses this private method,
139
+ # see https://github.com/rsim/oracle-enhanced/issues/2186
138
140
  def visit_Arel_Nodes_SelectOptions(o, collector)
139
141
  collector = maybe_visit o.limit, collector
140
142
  collector = maybe_visit o.offset, collector
@@ -243,6 +245,13 @@ module Arel # :nodoc: all
243
245
  collector << ")"
244
246
  end
245
247
 
248
+ def visit_Arel_Nodes_Filter(o, collector)
249
+ visit o.left, collector
250
+ collector << " FILTER (WHERE "
251
+ visit o.right, collector
252
+ collector << ")"
253
+ end
254
+
246
255
  def visit_Arel_Nodes_Rows(o, collector)
247
256
  if o.expr
248
257
  collector << "ROWS "
@@ -324,7 +333,7 @@ module Arel # :nodoc: all
324
333
  def visit_Arel_Nodes_HomogeneousIn(o, collector)
325
334
  collector.preparable = false
326
335
 
327
- collector << quote_table_name(o.table_name) << "." << quote_column_name(o.column_name)
336
+ visit o.left, collector
328
337
 
329
338
  if o.type == :in
330
339
  collector << " IN ("
@@ -341,7 +350,6 @@ module Arel # :nodoc: all
341
350
  end
342
351
 
343
352
  collector << ")"
344
- collector
345
353
  end
346
354
 
347
355
  def visit_Arel_SelectManager(o, collector)
@@ -357,6 +365,17 @@ module Arel # :nodoc: all
357
365
  visit(o.expr, collector) << " DESC"
358
366
  end
359
367
 
368
+ # NullsFirst is available on all but MySQL, where it is redefined.
369
+ def visit_Arel_Nodes_NullsFirst(o, collector)
370
+ visit o.expr, collector
371
+ collector << " NULLS FIRST"
372
+ end
373
+
374
+ def visit_Arel_Nodes_NullsLast(o, collector)
375
+ visit o.expr, collector
376
+ collector << " NULLS LAST"
377
+ end
378
+
360
379
  def visit_Arel_Nodes_Group(o, collector)
361
380
  visit o.expr, collector
362
381
  end
@@ -412,24 +431,48 @@ module Arel # :nodoc: all
412
431
  end
413
432
 
414
433
  def visit_Arel_Nodes_GreaterThanOrEqual(o, collector)
434
+ case unboundable?(o.right)
435
+ when 1
436
+ return collector << "1=0"
437
+ when -1
438
+ return collector << "1=1"
439
+ end
415
440
  collector = visit o.left, collector
416
441
  collector << " >= "
417
442
  visit o.right, collector
418
443
  end
419
444
 
420
445
  def visit_Arel_Nodes_GreaterThan(o, collector)
446
+ case unboundable?(o.right)
447
+ when 1
448
+ return collector << "1=0"
449
+ when -1
450
+ return collector << "1=1"
451
+ end
421
452
  collector = visit o.left, collector
422
453
  collector << " > "
423
454
  visit o.right, collector
424
455
  end
425
456
 
426
457
  def visit_Arel_Nodes_LessThanOrEqual(o, collector)
458
+ case unboundable?(o.right)
459
+ when 1
460
+ return collector << "1=1"
461
+ when -1
462
+ return collector << "1=0"
463
+ end
427
464
  collector = visit o.left, collector
428
465
  collector << " <= "
429
466
  visit o.right, collector
430
467
  end
431
468
 
432
469
  def visit_Arel_Nodes_LessThan(o, collector)
470
+ case unboundable?(o.right)
471
+ when 1
472
+ return collector << "1=1"
473
+ when -1
474
+ return collector << "1=0"
475
+ end
433
476
  collector = visit o.left, collector
434
477
  collector << " < "
435
478
  visit o.right, collector
@@ -525,11 +568,17 @@ module Arel # :nodoc: all
525
568
  end
526
569
 
527
570
  def visit_Arel_Table(o, collector)
528
- if o.table_alias
529
- collector << quote_table_name(o.name) << " " << quote_table_name(o.table_alias)
571
+ if Arel::Nodes::Node === o.name
572
+ visit o.name, collector
530
573
  else
531
574
  collector << quote_table_name(o.name)
532
575
  end
576
+
577
+ if o.table_alias
578
+ collector << " " << quote_table_name(o.table_alias)
579
+ end
580
+
581
+ collector
533
582
  end
534
583
 
535
584
  def visit_Arel_Nodes_In(o, collector)
@@ -585,7 +634,7 @@ module Arel # :nodoc: all
585
634
 
586
635
  def visit_Arel_Nodes_Assignment(o, collector)
587
636
  case o.right
588
- when Arel::Nodes::Node, Arel::Attributes::Attribute
637
+ when Arel::Nodes::Node, Arel::Attributes::Attribute, ActiveModel::Attribute
589
638
  collector = visit o.left, collector
590
639
  collector << " = "
591
640
  visit o.right, collector
@@ -685,6 +734,20 @@ module Arel # :nodoc: all
685
734
  collector << quote_column_name(o.name)
686
735
  end
687
736
 
737
+ def visit_Arel_Nodes_Cte(o, collector)
738
+ collector << quote_table_name(o.name)
739
+ collector << " AS "
740
+
741
+ case o.materialized
742
+ when true
743
+ collector << "MATERIALIZED "
744
+ when false
745
+ collector << "NOT MATERIALIZED "
746
+ end
747
+
748
+ visit o.relation, collector
749
+ end
750
+
688
751
  def visit_Arel_Attributes_Attribute(o, collector)
689
752
  join_name = o.relation.table_alias || o.relation.name
690
753
  collector << quote_table_name(join_name) << "." << quote_column_name(o.name)
@@ -695,6 +758,10 @@ module Arel # :nodoc: all
695
758
 
696
759
  def bind_block; BIND_BLOCK; end
697
760
 
761
+ def visit_ActiveModel_Attribute(o, collector)
762
+ collector.add_bind(o, &bind_block)
763
+ end
764
+
698
765
  def visit_Arel_Nodes_BindParam(o, collector)
699
766
  collector.add_bind(o.value, &bind_block)
700
767
  end
@@ -704,6 +771,59 @@ module Arel # :nodoc: all
704
771
  collector << o.to_s
705
772
  end
706
773
 
774
+ def visit_Arel_Nodes_BoundSqlLiteral(o, collector)
775
+ bind_index = 0
776
+
777
+ new_bind = lambda do |value|
778
+ if Arel.arel_node?(value)
779
+ visit value, collector
780
+ elsif value.is_a?(Array)
781
+ if value.empty?
782
+ collector << @connection.quote(nil)
783
+ else
784
+ if value.none? { |v| Arel.arel_node?(v) }
785
+ collector.add_binds(value.map { |v| @connection.cast_bound_value(v) }, &bind_block)
786
+ else
787
+ value.each_with_index do |v, i|
788
+ collector << ", " unless i == 0
789
+ if Arel.arel_node?(v)
790
+ visit v, collector
791
+ else
792
+ collector.add_bind(@connection.cast_bound_value(v), &bind_block)
793
+ end
794
+ end
795
+ end
796
+ end
797
+ else
798
+ collector.add_bind(@connection.cast_bound_value(value), &bind_block)
799
+ end
800
+ end
801
+
802
+ if o.positional_binds
803
+ o.sql_with_placeholders.scan(/\?|([^?]+)/) do
804
+ if $1
805
+ collector << $1
806
+ else
807
+ value = o.positional_binds[bind_index]
808
+ bind_index += 1
809
+
810
+ new_bind.call(value)
811
+ end
812
+ end
813
+ else
814
+ o.sql_with_placeholders.scan(/:(?<!::)([a-zA-Z]\w*)|([^:]+|.)/) do
815
+ if $2
816
+ collector << $2
817
+ else
818
+ value = o.named_binds[$1.to_sym]
819
+ new_bind.call(value)
820
+ end
821
+ end
822
+ end
823
+
824
+ collector
825
+ end
826
+
707
827
  def visit_Integer(o, collector)
708
828
  collector << o.to_s
709
829
  end
@@ -743,6 +863,10 @@ module Arel # :nodoc: all
743
863
  end
744
864
  alias :visit_Set :visit_Array
745
865
 
866
+ def visit_Arel_Nodes_Fragments(o, collector)
867
+ inject_join o.values, collector, " "
868
+ end
869
+
746
870
  def quote(value)
747
871
  return value if Arel::Nodes::SqlLiteral === value
748
872
  @connection.quote value
@@ -793,6 +917,10 @@ module Arel # :nodoc: all
793
917
  o.limit || o.offset || !o.orders.empty?
794
918
  end
795
919
 
920
+ def has_group_by_and_having?(o)
921
+ !o.groups.empty? && !o.havings.empty?
922
+ end
923
+
796
924
  # The default strategy for an UPDATE with joins is to use a subquery. This doesn't work
797
925
  # on MySQL (even when aliasing the tables), but MySQL allows using JOIN directly in
798
926
  # an UPDATE statement, so in the MySQL visitor we redefine this to do that.
@@ -802,8 +930,11 @@ module Arel # :nodoc: all
802
930
  stmt.limit = nil
803
931
  stmt.offset = nil
804
932
  stmt.orders = []
805
- stmt.wheres = [Nodes::In.new(o.key, [build_subselect(o.key, o)])]
933
+ columns = Arel::Nodes::Grouping.new(o.key)
934
+ stmt.wheres = [Nodes::In.new(columns, [build_subselect(o.key, o)])]
806
935
  stmt.relation = o.relation.left if has_join_sources?(o)
936
+ stmt.groups = o.groups unless o.groups.empty?
937
+ stmt.havings = o.havings unless o.havings.empty?
807
938
  stmt
808
939
  else
809
940
  o
@@ -818,6 +949,8 @@ module Arel # :nodoc: all
818
949
  core.froms = o.relation
819
950
  core.wheres = o.wheres
820
951
  core.projections = [key]
952
+ core.groups = o.groups unless o.groups.empty?
953
+ core.havings = o.havings unless o.havings.empty?
821
954
  stmt.limit = o.limit
822
955
  stmt.offset = o.offset
823
956
  stmt.orders = o.orders
@@ -877,19 +1010,7 @@ module Arel # :nodoc: all
877
1010
  def collect_ctes(children, collector)
878
1011
  children.each_with_index do |child, i|
879
1012
  collector << ", " unless i == 0
880
-
881
- case child
882
- when Arel::Nodes::As
883
- name = child.left.name
884
- relation = child.right
885
- when Arel::Nodes::TableAlias
886
- name = child.name
887
- relation = child.relation
888
- end
889
-
890
- collector << quote_table_name(name)
891
- collector << " AS "
892
- visit relation, collector
1013
+ visit child.to_cte, collector
893
1014
  end
894
1015
 
895
1016
  collector
@@ -16,8 +16,8 @@ module Arel # :nodoc: all
16
16
 
17
17
  def self.dispatch_cache
18
18
  @dispatch_cache ||= Hash.new do |hash, klass|
19
- hash[klass] = "visit_#{(klass.name || '').gsub('::', '_')}"
20
- end
19
+ hash[klass] = :"visit_#{(klass.name || "").gsub("::", "_")}"
20
+ end.compare_by_identity
21
21
  end
22
22
 
23
23
  def get_dispatch_cache
data/lib/arel.rb CHANGED
@@ -7,6 +7,7 @@ require "arel/factory_methods"
7
7
 
8
8
  require "arel/expressions"
9
9
  require "arel/predications"
10
+ require "arel/filter_predications"
10
11
  require "arel/window_predications"
11
12
  require "arel/math"
12
13
  require "arel/alias_predication"
@@ -29,13 +30,27 @@ module Arel
29
30
 
30
31
  # Wrap a known-safe SQL string for passing to query methods, e.g.
31
32
  #
32
- # Post.order(Arel.sql("length(title)")).last
33
+ # Post.order(Arel.sql("REPLACE(title, 'misc', 'zzzz') asc")).pluck(:id)
33
34
  #
34
35
  # Great caution should be taken to avoid SQL injection vulnerabilities.
35
36
  # This method should not be used with unsafe values such as request
36
37
  # parameters or model attributes.
37
- def self.sql(raw_sql)
38
- Arel::Nodes::SqlLiteral.new raw_sql
38
+ #
39
+ # Take a look at the {security guide}[https://guides.rubyonrails.org/security.html#sql-injection]
40
+ # for more information.
41
+ #
42
+ # To construct a more complex query fragment, including the possible
43
+ # use of user-provided values, the +sql_string+ may contain <tt>?</tt> and
44
+ # +:key+ placeholders, corresponding to the additional arguments. Note
45
+ # that this behavior only applies when bind value parameters are
46
+ # supplied in the call; without them, the placeholder tokens have no
47
+ # special meaning, and will be passed through to the query as-is.
48
+ def self.sql(sql_string, *positional_binds, **named_binds)
49
+ if positional_binds.empty? && named_binds.empty?
50
+ Arel::Nodes::SqlLiteral.new sql_string
51
+ else
52
+ Arel::Nodes::BoundSqlLiteral.new sql_string, positional_binds, named_binds
53
+ end
39
54
  end
40
55
 
41
56
  def self.star # :nodoc:
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Generates an `ApplicationRecord` base class for other models to inherit from.
3
+
4
+ Example:
5
+ `bin/rails generate application_record`
6
+
7
+ This generates the base class. A test is not generated because no
8
+ behaviour is included in `ApplicationRecord` by default.
@@ -1,5 +1,5 @@
1
1
  <% module_namespacing do -%>
2
2
  class ApplicationRecord < ActiveRecord::Base
3
- self.abstract_class = true
3
+ primary_abstract_class
4
4
  end
5
5
  <% end -%>