activerecord 3.2.6 → 6.0.0

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

Potentially problematic release.


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

Files changed (371) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +611 -6417
  3. data/MIT-LICENSE +4 -2
  4. data/README.rdoc +44 -47
  5. data/examples/performance.rb +79 -71
  6. data/examples/simple.rb +6 -5
  7. data/lib/active_record/aggregations.rb +268 -238
  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 +173 -81
  11. data/lib/active_record/associations/association_scope.rb +124 -92
  12. data/lib/active_record/associations/belongs_to_association.rb +83 -38
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +11 -9
  14. data/lib/active_record/associations/builder/association.rb +113 -32
  15. data/lib/active_record/associations/builder/belongs_to.rb +105 -60
  16. data/lib/active_record/associations/builder/collection_association.rb +53 -56
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +98 -41
  18. data/lib/active_record/associations/builder/has_many.rb +11 -63
  19. data/lib/active_record/associations/builder/has_one.rb +47 -45
  20. data/lib/active_record/associations/builder/singular_association.rb +30 -18
  21. data/lib/active_record/associations/collection_association.rb +217 -295
  22. data/lib/active_record/associations/collection_proxy.rb +1074 -77
  23. data/lib/active_record/associations/foreign_association.rb +20 -0
  24. data/lib/active_record/associations/has_many_association.rb +78 -50
  25. data/lib/active_record/associations/has_many_through_association.rb +99 -61
  26. data/lib/active_record/associations/has_one_association.rb +75 -30
  27. data/lib/active_record/associations/has_one_through_association.rb +20 -11
  28. data/lib/active_record/associations/join_dependency/join_association.rb +45 -119
  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 +208 -164
  32. data/lib/active_record/associations/preloader/association.rb +93 -87
  33. data/lib/active_record/associations/preloader/through_association.rb +87 -38
  34. data/lib/active_record/associations/preloader.rb +134 -110
  35. data/lib/active_record/associations/singular_association.rb +19 -24
  36. data/lib/active_record/associations/through_association.rb +61 -27
  37. data/lib/active_record/associations.rb +1766 -1505
  38. data/lib/active_record/attribute_assignment.rb +57 -193
  39. data/lib/active_record/attribute_decorators.rb +90 -0
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +58 -8
  41. data/lib/active_record/attribute_methods/dirty.rb +187 -67
  42. data/lib/active_record/attribute_methods/primary_key.rb +100 -78
  43. data/lib/active_record/attribute_methods/query.rb +10 -8
  44. data/lib/active_record/attribute_methods/read.rb +29 -118
  45. data/lib/active_record/attribute_methods/serialization.rb +60 -72
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +69 -42
  47. data/lib/active_record/attribute_methods/write.rb +36 -44
  48. data/lib/active_record/attribute_methods.rb +306 -161
  49. data/lib/active_record/attributes.rb +279 -0
  50. data/lib/active_record/autosave_association.rb +324 -238
  51. data/lib/active_record/base.rb +114 -507
  52. data/lib/active_record/callbacks.rb +147 -83
  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/connection_adapters/abstract/connection_pool.rb +962 -279
  56. data/lib/active_record/connection_adapters/abstract/database_limits.rb +32 -5
  57. data/lib/active_record/connection_adapters/abstract/database_statements.rb +331 -209
  58. data/lib/active_record/connection_adapters/abstract/query_cache.rb +95 -23
  59. data/lib/active_record/connection_adapters/abstract/quoting.rb +201 -65
  60. data/lib/active_record/connection_adapters/abstract/savepoints.rb +23 -0
  61. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -0
  62. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +510 -289
  63. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +93 -0
  64. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1182 -313
  65. data/lib/active_record/connection_adapters/abstract/transaction.rb +323 -0
  66. data/lib/active_record/connection_adapters/abstract_adapter.rb +585 -120
  67. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +610 -463
  68. data/lib/active_record/connection_adapters/column.rb +58 -233
  69. data/lib/active_record/connection_adapters/connection_specification.rb +297 -0
  70. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +29 -0
  71. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  72. data/lib/active_record/connection_adapters/mysql/database_statements.rb +200 -0
  73. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  74. data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +72 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +95 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +88 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +264 -0
  79. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +31 -0
  80. data/lib/active_record/connection_adapters/mysql2_adapter.rb +75 -207
  81. data/lib/active_record/connection_adapters/postgresql/column.rb +30 -0
  82. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +182 -0
  83. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +92 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +53 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +15 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +17 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +50 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +23 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +15 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +21 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +71 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +15 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +15 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +41 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +15 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +65 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +97 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +18 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +113 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +28 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +30 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid.rb +34 -0
  107. data/lib/active_record/connection_adapters/postgresql/quoting.rb +205 -0
  108. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +43 -0
  109. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +76 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +222 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +776 -0
  113. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +36 -0
  114. data/lib/active_record/connection_adapters/postgresql/utils.rb +81 -0
  115. data/lib/active_record/connection_adapters/postgresql_adapter.rb +695 -1052
  116. data/lib/active_record/connection_adapters/schema_cache.rb +115 -24
  117. data/lib/active_record/connection_adapters/sql_type_metadata.rb +37 -0
  118. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -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 +103 -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 +137 -0
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +528 -26
  126. data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
  127. data/lib/active_record/connection_handling.rb +267 -0
  128. data/lib/active_record/core.rb +599 -0
  129. data/lib/active_record/counter_cache.rb +177 -103
  130. data/lib/active_record/database_configurations/database_config.rb +37 -0
  131. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  132. data/lib/active_record/database_configurations/url_config.rb +79 -0
  133. data/lib/active_record/database_configurations.rb +233 -0
  134. data/lib/active_record/define_callbacks.rb +22 -0
  135. data/lib/active_record/dynamic_matchers.rb +107 -64
  136. data/lib/active_record/enum.rb +274 -0
  137. data/lib/active_record/errors.rb +254 -61
  138. data/lib/active_record/explain.rb +35 -70
  139. data/lib/active_record/explain_registry.rb +32 -0
  140. data/lib/active_record/explain_subscriber.rb +18 -8
  141. data/lib/active_record/fixture_set/file.rb +82 -0
  142. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  143. data/lib/active_record/fixture_set/render_context.rb +17 -0
  144. data/lib/active_record/fixture_set/table_row.rb +153 -0
  145. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  146. data/lib/active_record/fixtures.rb +291 -475
  147. data/lib/active_record/gem_version.rb +17 -0
  148. data/lib/active_record/inheritance.rb +219 -100
  149. data/lib/active_record/insert_all.rb +179 -0
  150. data/lib/active_record/integration.rb +175 -17
  151. data/lib/active_record/internal_metadata.rb +53 -0
  152. data/lib/active_record/legacy_yaml_adapter.rb +48 -0
  153. data/lib/active_record/locale/en.yml +9 -1
  154. data/lib/active_record/locking/optimistic.rb +106 -92
  155. data/lib/active_record/locking/pessimistic.rb +23 -11
  156. data/lib/active_record/log_subscriber.rb +80 -30
  157. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  158. data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
  159. data/lib/active_record/middleware/database_selector.rb +75 -0
  160. data/lib/active_record/migration/command_recorder.rb +235 -56
  161. data/lib/active_record/migration/compatibility.rb +244 -0
  162. data/lib/active_record/migration/join_table.rb +17 -0
  163. data/lib/active_record/migration.rb +917 -301
  164. data/lib/active_record/model_schema.rb +351 -175
  165. data/lib/active_record/nested_attributes.rb +366 -235
  166. data/lib/active_record/no_touching.rb +65 -0
  167. data/lib/active_record/null_relation.rb +68 -0
  168. data/lib/active_record/persistence.rb +761 -166
  169. data/lib/active_record/query_cache.rb +22 -44
  170. data/lib/active_record/querying.rb +55 -31
  171. data/lib/active_record/railtie.rb +185 -47
  172. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  173. data/lib/active_record/railties/console_sandbox.rb +5 -4
  174. data/lib/active_record/railties/controller_runtime.rb +35 -33
  175. data/lib/active_record/railties/databases.rake +366 -463
  176. data/lib/active_record/readonly_attributes.rb +4 -6
  177. data/lib/active_record/reflection.rb +736 -228
  178. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  179. data/lib/active_record/relation/batches.rb +252 -52
  180. data/lib/active_record/relation/calculations.rb +340 -270
  181. data/lib/active_record/relation/delegation.rb +117 -36
  182. data/lib/active_record/relation/finder_methods.rb +439 -286
  183. data/lib/active_record/relation/from_clause.rb +26 -0
  184. data/lib/active_record/relation/merger.rb +184 -0
  185. data/lib/active_record/relation/predicate_builder/array_handler.rb +49 -0
  186. data/lib/active_record/relation/predicate_builder/association_query_value.rb +43 -0
  187. data/lib/active_record/relation/predicate_builder/base_handler.rb +18 -0
  188. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +19 -0
  189. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +53 -0
  190. data/lib/active_record/relation/predicate_builder/range_handler.rb +22 -0
  191. data/lib/active_record/relation/predicate_builder/relation_handler.rb +19 -0
  192. data/lib/active_record/relation/predicate_builder.rb +131 -39
  193. data/lib/active_record/relation/query_attribute.rb +50 -0
  194. data/lib/active_record/relation/query_methods.rb +1163 -221
  195. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  196. data/lib/active_record/relation/spawn_methods.rb +49 -120
  197. data/lib/active_record/relation/where_clause.rb +190 -0
  198. data/lib/active_record/relation/where_clause_factory.rb +33 -0
  199. data/lib/active_record/relation.rb +671 -349
  200. data/lib/active_record/result.rb +149 -15
  201. data/lib/active_record/runtime_registry.rb +24 -0
  202. data/lib/active_record/sanitization.rb +153 -133
  203. data/lib/active_record/schema.rb +22 -19
  204. data/lib/active_record/schema_dumper.rb +178 -112
  205. data/lib/active_record/schema_migration.rb +60 -0
  206. data/lib/active_record/scoping/default.rb +107 -98
  207. data/lib/active_record/scoping/named.rb +130 -115
  208. data/lib/active_record/scoping.rb +77 -123
  209. data/lib/active_record/secure_token.rb +40 -0
  210. data/lib/active_record/serialization.rb +10 -6
  211. data/lib/active_record/statement_cache.rb +148 -0
  212. data/lib/active_record/store.rb +256 -16
  213. data/lib/active_record/suppressor.rb +61 -0
  214. data/lib/active_record/table_metadata.rb +75 -0
  215. data/lib/active_record/tasks/database_tasks.rb +506 -0
  216. data/lib/active_record/tasks/mysql_database_tasks.rb +115 -0
  217. data/lib/active_record/tasks/postgresql_database_tasks.rb +141 -0
  218. data/lib/active_record/tasks/sqlite_database_tasks.rb +77 -0
  219. data/lib/active_record/test_databases.rb +23 -0
  220. data/lib/active_record/test_fixtures.rb +224 -0
  221. data/lib/active_record/timestamp.rb +93 -39
  222. data/lib/active_record/touch_later.rb +66 -0
  223. data/lib/active_record/transactions.rb +260 -129
  224. data/lib/active_record/translation.rb +3 -1
  225. data/lib/active_record/type/adapter_specific_registry.rb +129 -0
  226. data/lib/active_record/type/date.rb +9 -0
  227. data/lib/active_record/type/date_time.rb +9 -0
  228. data/lib/active_record/type/decimal_without_scale.rb +15 -0
  229. data/lib/active_record/type/hash_lookup_type_map.rb +25 -0
  230. data/lib/active_record/type/internal/timezone.rb +17 -0
  231. data/lib/active_record/type/json.rb +30 -0
  232. data/lib/active_record/type/serialized.rb +71 -0
  233. data/lib/active_record/type/text.rb +11 -0
  234. data/lib/active_record/type/time.rb +21 -0
  235. data/lib/active_record/type/type_map.rb +62 -0
  236. data/lib/active_record/type/unsigned_integer.rb +17 -0
  237. data/lib/active_record/type.rb +78 -0
  238. data/lib/active_record/type_caster/connection.rb +34 -0
  239. data/lib/active_record/type_caster/map.rb +20 -0
  240. data/lib/active_record/type_caster.rb +9 -0
  241. data/lib/active_record/validations/absence.rb +25 -0
  242. data/lib/active_record/validations/associated.rb +35 -18
  243. data/lib/active_record/validations/length.rb +26 -0
  244. data/lib/active_record/validations/presence.rb +68 -0
  245. data/lib/active_record/validations/uniqueness.rb +123 -77
  246. data/lib/active_record/validations.rb +54 -43
  247. data/lib/active_record/version.rb +7 -7
  248. data/lib/active_record.rb +97 -49
  249. data/lib/arel/alias_predication.rb +9 -0
  250. data/lib/arel/attributes/attribute.rb +37 -0
  251. data/lib/arel/attributes.rb +22 -0
  252. data/lib/arel/collectors/bind.rb +24 -0
  253. data/lib/arel/collectors/composite.rb +31 -0
  254. data/lib/arel/collectors/plain_string.rb +20 -0
  255. data/lib/arel/collectors/sql_string.rb +20 -0
  256. data/lib/arel/collectors/substitute_binds.rb +28 -0
  257. data/lib/arel/crud.rb +42 -0
  258. data/lib/arel/delete_manager.rb +18 -0
  259. data/lib/arel/errors.rb +9 -0
  260. data/lib/arel/expressions.rb +29 -0
  261. data/lib/arel/factory_methods.rb +49 -0
  262. data/lib/arel/insert_manager.rb +49 -0
  263. data/lib/arel/math.rb +45 -0
  264. data/lib/arel/nodes/and.rb +32 -0
  265. data/lib/arel/nodes/ascending.rb +23 -0
  266. data/lib/arel/nodes/binary.rb +52 -0
  267. data/lib/arel/nodes/bind_param.rb +36 -0
  268. data/lib/arel/nodes/case.rb +55 -0
  269. data/lib/arel/nodes/casted.rb +50 -0
  270. data/lib/arel/nodes/comment.rb +29 -0
  271. data/lib/arel/nodes/count.rb +12 -0
  272. data/lib/arel/nodes/delete_statement.rb +45 -0
  273. data/lib/arel/nodes/descending.rb +23 -0
  274. data/lib/arel/nodes/equality.rb +18 -0
  275. data/lib/arel/nodes/extract.rb +24 -0
  276. data/lib/arel/nodes/false.rb +16 -0
  277. data/lib/arel/nodes/full_outer_join.rb +8 -0
  278. data/lib/arel/nodes/function.rb +44 -0
  279. data/lib/arel/nodes/grouping.rb +8 -0
  280. data/lib/arel/nodes/in.rb +8 -0
  281. data/lib/arel/nodes/infix_operation.rb +80 -0
  282. data/lib/arel/nodes/inner_join.rb +8 -0
  283. data/lib/arel/nodes/insert_statement.rb +37 -0
  284. data/lib/arel/nodes/join_source.rb +20 -0
  285. data/lib/arel/nodes/matches.rb +18 -0
  286. data/lib/arel/nodes/named_function.rb +23 -0
  287. data/lib/arel/nodes/node.rb +50 -0
  288. data/lib/arel/nodes/node_expression.rb +13 -0
  289. data/lib/arel/nodes/outer_join.rb +8 -0
  290. data/lib/arel/nodes/over.rb +15 -0
  291. data/lib/arel/nodes/regexp.rb +16 -0
  292. data/lib/arel/nodes/right_outer_join.rb +8 -0
  293. data/lib/arel/nodes/select_core.rb +67 -0
  294. data/lib/arel/nodes/select_statement.rb +41 -0
  295. data/lib/arel/nodes/sql_literal.rb +16 -0
  296. data/lib/arel/nodes/string_join.rb +11 -0
  297. data/lib/arel/nodes/table_alias.rb +27 -0
  298. data/lib/arel/nodes/terminal.rb +16 -0
  299. data/lib/arel/nodes/true.rb +16 -0
  300. data/lib/arel/nodes/unary.rb +45 -0
  301. data/lib/arel/nodes/unary_operation.rb +20 -0
  302. data/lib/arel/nodes/unqualified_column.rb +22 -0
  303. data/lib/arel/nodes/update_statement.rb +41 -0
  304. data/lib/arel/nodes/values_list.rb +9 -0
  305. data/lib/arel/nodes/window.rb +126 -0
  306. data/lib/arel/nodes/with.rb +11 -0
  307. data/lib/arel/nodes.rb +68 -0
  308. data/lib/arel/order_predications.rb +13 -0
  309. data/lib/arel/predications.rb +257 -0
  310. data/lib/arel/select_manager.rb +271 -0
  311. data/lib/arel/table.rb +110 -0
  312. data/lib/arel/tree_manager.rb +72 -0
  313. data/lib/arel/update_manager.rb +34 -0
  314. data/lib/arel/visitors/depth_first.rb +204 -0
  315. data/lib/arel/visitors/dot.rb +297 -0
  316. data/lib/arel/visitors/ibm_db.rb +34 -0
  317. data/lib/arel/visitors/informix.rb +62 -0
  318. data/lib/arel/visitors/mssql.rb +157 -0
  319. data/lib/arel/visitors/mysql.rb +83 -0
  320. data/lib/arel/visitors/oracle.rb +159 -0
  321. data/lib/arel/visitors/oracle12.rb +66 -0
  322. data/lib/arel/visitors/postgresql.rb +110 -0
  323. data/lib/arel/visitors/sqlite.rb +39 -0
  324. data/lib/arel/visitors/to_sql.rb +889 -0
  325. data/lib/arel/visitors/visitor.rb +46 -0
  326. data/lib/arel/visitors/where_sql.rb +23 -0
  327. data/lib/arel/visitors.rb +20 -0
  328. data/lib/arel/window_predications.rb +9 -0
  329. data/lib/arel.rb +51 -0
  330. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  331. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  332. data/lib/rails/generators/active_record/migration/migration_generator.rb +59 -9
  333. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +24 -0
  334. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +48 -0
  335. data/lib/rails/generators/active_record/migration.rb +41 -8
  336. data/lib/rails/generators/active_record/model/model_generator.rb +24 -22
  337. data/lib/rails/generators/active_record/model/templates/model.rb.tt +22 -0
  338. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +1 -1
  339. data/lib/rails/generators/active_record.rb +10 -16
  340. metadata +285 -149
  341. data/examples/associations.png +0 -0
  342. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
  343. data/lib/active_record/associations/join_helper.rb +0 -55
  344. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  345. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  346. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  347. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  348. data/lib/active_record/associations/preloader/has_many_through.rb +0 -15
  349. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  350. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  351. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  352. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  353. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -188
  354. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -426
  355. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -579
  356. data/lib/active_record/dynamic_finder_match.rb +0 -68
  357. data/lib/active_record/dynamic_scope_match.rb +0 -23
  358. data/lib/active_record/fixtures/file.rb +0 -65
  359. data/lib/active_record/identity_map.rb +0 -162
  360. data/lib/active_record/observer.rb +0 -121
  361. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  362. data/lib/active_record/serializers/xml_serializer.rb +0 -203
  363. data/lib/active_record/session_store.rb +0 -358
  364. data/lib/active_record/test_case.rb +0 -73
  365. data/lib/rails/generators/active_record/migration/templates/migration.rb +0 -34
  366. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
  367. data/lib/rails/generators/active_record/model/templates/model.rb +0 -12
  368. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  369. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  370. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  371. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -1,55 +1,557 @@
1
- require 'active_record/connection_adapters/sqlite_adapter'
1
+ # frozen_string_literal: true
2
2
 
3
- gem 'sqlite3', '~> 1.3.5'
4
- require 'sqlite3'
3
+ require "active_record/connection_adapters/abstract_adapter"
4
+ require "active_record/connection_adapters/statement_pool"
5
+ require "active_record/connection_adapters/sqlite3/explain_pretty_printer"
6
+ require "active_record/connection_adapters/sqlite3/quoting"
7
+ require "active_record/connection_adapters/sqlite3/database_statements"
8
+ require "active_record/connection_adapters/sqlite3/schema_creation"
9
+ require "active_record/connection_adapters/sqlite3/schema_definitions"
10
+ require "active_record/connection_adapters/sqlite3/schema_dumper"
11
+ require "active_record/connection_adapters/sqlite3/schema_statements"
12
+
13
+ gem "sqlite3", "~> 1.4"
14
+ require "sqlite3"
5
15
 
6
16
  module ActiveRecord
7
- class Base
8
- # sqlite3 adapter reuses sqlite_connection.
9
- def self.sqlite3_connection(config) # :nodoc:
17
+ module ConnectionHandling # :nodoc:
18
+ def sqlite3_connection(config)
19
+ config = config.symbolize_keys
20
+
10
21
  # Require database.
11
22
  unless config[:database]
12
23
  raise ArgumentError, "No database file specified. Missing argument: database"
13
24
  end
14
25
 
15
- # Allow database path relative to Rails.root, but only if
16
- # the database path is not the special path that tells
17
- # Sqlite to build a database only in memory.
18
- if defined?(Rails.root) && ':memory:' != config[:database]
19
- config[:database] = File.expand_path(config[:database], Rails.root)
20
- end
21
-
22
- unless 'sqlite3' == config[:adapter]
23
- raise ArgumentError, 'adapter name should be "sqlite3"'
26
+ # Allow database path relative to Rails.root, but only if the database
27
+ # path is not the special path that tells sqlite to build a database only
28
+ # in memory.
29
+ if ":memory:" != config[:database]
30
+ config[:database] = File.expand_path(config[:database], Rails.root) if defined?(Rails.root)
31
+ dirname = File.dirname(config[:database])
32
+ Dir.mkdir(dirname) unless File.directory?(dirname)
24
33
  end
25
34
 
26
35
  db = SQLite3::Database.new(
27
- config[:database],
28
- :results_as_hash => true
36
+ config[:database].to_s,
37
+ config.merge(results_as_hash: true)
29
38
  )
30
39
 
31
- db.busy_timeout(config[:timeout]) if config[:timeout]
32
-
33
- ConnectionAdapters::SQLite3Adapter.new(db, logger, config)
40
+ ConnectionAdapters::SQLite3Adapter.new(db, logger, nil, config)
41
+ rescue Errno::ENOENT => error
42
+ if error.message.include?("No such file or directory")
43
+ raise ActiveRecord::NoDatabaseError
44
+ else
45
+ raise
46
+ end
34
47
  end
35
48
  end
36
49
 
37
50
  module ConnectionAdapters #:nodoc:
38
- class SQLite3Adapter < SQLiteAdapter # :nodoc:
39
- def quote(value, column = nil)
40
- if value.kind_of?(String) && column && column.type == :binary && column.class.respond_to?(:string_to_binary)
41
- s = column.class.string_to_binary(value).unpack("H*")[0]
42
- "x'#{s}'"
51
+ # The SQLite3 adapter works SQLite 3.6.16 or newer
52
+ # with the sqlite3-ruby drivers (available as gem from https://rubygems.org/gems/sqlite3).
53
+ #
54
+ # Options:
55
+ #
56
+ # * <tt>:database</tt> - Path to the database file.
57
+ class SQLite3Adapter < AbstractAdapter
58
+ ADAPTER_NAME = "SQLite"
59
+
60
+ include SQLite3::Quoting
61
+ include SQLite3::SchemaStatements
62
+ include SQLite3::DatabaseStatements
63
+
64
+ NATIVE_DATABASE_TYPES = {
65
+ primary_key: "integer PRIMARY KEY AUTOINCREMENT NOT NULL",
66
+ string: { name: "varchar" },
67
+ text: { name: "text" },
68
+ integer: { name: "integer" },
69
+ float: { name: "float" },
70
+ decimal: { name: "decimal" },
71
+ datetime: { name: "datetime" },
72
+ time: { name: "time" },
73
+ date: { name: "date" },
74
+ binary: { name: "blob" },
75
+ boolean: { name: "boolean" },
76
+ json: { name: "json" },
77
+ }
78
+
79
+ def self.represent_boolean_as_integer=(value) # :nodoc:
80
+ if value == false
81
+ raise "`.represent_boolean_as_integer=` is now always true, so make sure your application can work with it and remove this settings."
82
+ end
83
+
84
+ ActiveSupport::Deprecation.warn(
85
+ "`.represent_boolean_as_integer=` is now always true, so setting this is deprecated and will be removed in Rails 6.1."
86
+ )
87
+ end
88
+
89
+ class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
90
+ private
91
+ def dealloc(stmt)
92
+ stmt.close unless stmt.closed?
93
+ end
94
+ end
95
+
96
+ def initialize(connection, logger, connection_options, config)
97
+ super(connection, logger, config)
98
+ configure_connection
99
+ end
100
+
101
+ def self.database_exists?(config)
102
+ config = config.symbolize_keys
103
+ if config[:database] == ":memory:"
104
+ return true
43
105
  else
44
- super
106
+ database_file = defined?(Rails.root) ? File.expand_path(config[:database], Rails.root) : config[:database]
107
+ File.exist?(database_file)
45
108
  end
46
109
  end
47
110
 
111
+ def supports_ddl_transactions?
112
+ true
113
+ end
114
+
115
+ def supports_savepoints?
116
+ true
117
+ end
118
+
119
+ def supports_partial_index?
120
+ true
121
+ end
122
+
123
+ def supports_expression_index?
124
+ database_version >= "3.9.0"
125
+ end
126
+
127
+ def requires_reloading?
128
+ true
129
+ end
130
+
131
+ def supports_foreign_keys?
132
+ true
133
+ end
134
+
135
+ def supports_views?
136
+ true
137
+ end
138
+
139
+ def supports_datetime_with_precision?
140
+ true
141
+ end
142
+
143
+ def supports_json?
144
+ true
145
+ end
146
+
147
+ def supports_insert_on_conflict?
148
+ database_version >= "3.24.0"
149
+ end
150
+ alias supports_insert_on_duplicate_skip? supports_insert_on_conflict?
151
+ alias supports_insert_on_duplicate_update? supports_insert_on_conflict?
152
+ alias supports_insert_conflict_target? supports_insert_on_conflict?
153
+
154
+ def active?
155
+ !@connection.closed?
156
+ end
157
+
158
+ def reconnect!
159
+ super
160
+ connect if @connection.closed?
161
+ end
162
+
163
+ # Disconnects from the database if already connected. Otherwise, this
164
+ # method does nothing.
165
+ def disconnect!
166
+ super
167
+ @connection.close rescue nil
168
+ end
169
+
170
+ def supports_index_sort_order?
171
+ true
172
+ end
173
+
174
+ # Returns 62. SQLite supports index names up to 64
175
+ # characters. The rest is used by Rails internally to perform
176
+ # temporary rename operations
177
+ def allowed_index_name_length
178
+ index_name_length - 2
179
+ end
180
+
181
+ def native_database_types #:nodoc:
182
+ NATIVE_DATABASE_TYPES
183
+ end
184
+
48
185
  # Returns the current database encoding format as a string, eg: 'UTF-8'
49
186
  def encoding
50
187
  @connection.encoding.to_s
51
188
  end
52
189
 
190
+ def supports_explain?
191
+ true
192
+ end
193
+
194
+ def supports_lazy_transactions?
195
+ true
196
+ end
197
+
198
+ # REFERENTIAL INTEGRITY ====================================
199
+
200
+ def disable_referential_integrity # :nodoc:
201
+ old_foreign_keys = query_value("PRAGMA foreign_keys")
202
+ old_defer_foreign_keys = query_value("PRAGMA defer_foreign_keys")
203
+
204
+ begin
205
+ execute("PRAGMA defer_foreign_keys = ON")
206
+ execute("PRAGMA foreign_keys = OFF")
207
+ yield
208
+ ensure
209
+ execute("PRAGMA defer_foreign_keys = #{old_defer_foreign_keys}")
210
+ execute("PRAGMA foreign_keys = #{old_foreign_keys}")
211
+ end
212
+ end
213
+
214
+ #--
215
+ # DATABASE STATEMENTS ======================================
216
+ #++
217
+ def explain(arel, binds = [])
218
+ sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
219
+ SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", []))
220
+ end
221
+
222
+ # SCHEMA STATEMENTS ========================================
223
+
224
+ def primary_keys(table_name) # :nodoc:
225
+ pks = table_structure(table_name).select { |f| f["pk"] > 0 }
226
+ pks.sort_by { |f| f["pk"] }.map { |f| f["name"] }
227
+ end
228
+
229
+ def remove_index(table_name, options = {}) #:nodoc:
230
+ index_name = index_name_for_remove(table_name, options)
231
+ exec_query "DROP INDEX #{quote_column_name(index_name)}"
232
+ end
233
+
234
+ # Renames a table.
235
+ #
236
+ # Example:
237
+ # rename_table('octopuses', 'octopi')
238
+ def rename_table(table_name, new_name)
239
+ exec_query "ALTER TABLE #{quote_table_name(table_name)} RENAME TO #{quote_table_name(new_name)}"
240
+ rename_table_indexes(table_name, new_name)
241
+ end
242
+
243
+ def add_column(table_name, column_name, type, options = {}) #:nodoc:
244
+ if invalid_alter_table_type?(type, options)
245
+ alter_table(table_name) do |definition|
246
+ definition.column(column_name, type, options)
247
+ end
248
+ else
249
+ super
250
+ end
251
+ end
252
+
253
+ def remove_column(table_name, column_name, type = nil, options = {}) #:nodoc:
254
+ alter_table(table_name) do |definition|
255
+ definition.remove_column column_name
256
+ definition.foreign_keys.delete_if do |_, fk_options|
257
+ fk_options[:column] == column_name.to_s
258
+ end
259
+ end
260
+ end
261
+
262
+ def change_column_default(table_name, column_name, default_or_changes) #:nodoc:
263
+ default = extract_new_default_value(default_or_changes)
264
+
265
+ alter_table(table_name) do |definition|
266
+ definition[column_name].default = default
267
+ end
268
+ end
269
+
270
+ def change_column_null(table_name, column_name, null, default = nil) #:nodoc:
271
+ unless null || default.nil?
272
+ exec_query("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
273
+ end
274
+ alter_table(table_name) do |definition|
275
+ definition[column_name].null = null
276
+ end
277
+ end
278
+
279
+ def change_column(table_name, column_name, type, options = {}) #:nodoc:
280
+ alter_table(table_name) do |definition|
281
+ definition[column_name].instance_eval do
282
+ self.type = type
283
+ self.limit = options[:limit] if options.include?(:limit)
284
+ self.default = options[:default] if options.include?(:default)
285
+ self.null = options[:null] if options.include?(:null)
286
+ self.precision = options[:precision] if options.include?(:precision)
287
+ self.scale = options[:scale] if options.include?(:scale)
288
+ self.collation = options[:collation] if options.include?(:collation)
289
+ end
290
+ end
291
+ end
292
+
293
+ def rename_column(table_name, column_name, new_column_name) #:nodoc:
294
+ column = column_for(table_name, column_name)
295
+ alter_table(table_name, rename: { column.name => new_column_name.to_s })
296
+ rename_column_indexes(table_name, column.name, new_column_name)
297
+ end
298
+
299
+ def add_reference(table_name, ref_name, **options) # :nodoc:
300
+ super(table_name, ref_name, type: :integer, **options)
301
+ end
302
+ alias :add_belongs_to :add_reference
303
+
304
+ def foreign_keys(table_name)
305
+ fk_info = exec_query("PRAGMA foreign_key_list(#{quote(table_name)})", "SCHEMA")
306
+ fk_info.map do |row|
307
+ options = {
308
+ column: row["from"],
309
+ primary_key: row["to"],
310
+ on_delete: extract_foreign_key_action(row["on_delete"]),
311
+ on_update: extract_foreign_key_action(row["on_update"])
312
+ }
313
+ ForeignKeyDefinition.new(table_name, row["table"], options)
314
+ end
315
+ end
316
+
317
+ def build_insert_sql(insert) # :nodoc:
318
+ sql = +"INSERT #{insert.into} #{insert.values_list}"
319
+
320
+ if insert.skip_duplicates?
321
+ sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
322
+ elsif insert.update_duplicates?
323
+ sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
324
+ sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
325
+ end
326
+
327
+ sql
328
+ end
329
+
330
+ def get_database_version # :nodoc:
331
+ SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)"))
332
+ end
333
+
334
+ def check_version # :nodoc:
335
+ if database_version < "3.8.0"
336
+ raise "Your version of SQLite (#{database_version}) is too old. Active Record supports SQLite >= 3.8."
337
+ end
338
+ end
339
+
340
+ private
341
+ # See https://www.sqlite.org/limits.html,
342
+ # the default value is 999 when not configured.
343
+ def bind_params_length
344
+ 999
345
+ end
346
+
347
+ def initialize_type_map(m = type_map)
348
+ super
349
+ register_class_with_limit m, %r(int)i, SQLite3Integer
350
+ end
351
+
352
+ def table_structure(table_name)
353
+ structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", "SCHEMA")
354
+ raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
355
+ table_structure_with_collation(table_name, structure)
356
+ end
357
+ alias column_definitions table_structure
358
+
359
+ # See: https://www.sqlite.org/lang_altertable.html
360
+ # SQLite has an additional restriction on the ALTER TABLE statement
361
+ def invalid_alter_table_type?(type, options)
362
+ type.to_sym == :primary_key || options[:primary_key]
363
+ end
364
+
365
+ def alter_table(table_name, foreign_keys = foreign_keys(table_name), **options)
366
+ altered_table_name = "a#{table_name}"
367
+
368
+ caller = lambda do |definition|
369
+ rename = options[:rename] || {}
370
+ foreign_keys.each do |fk|
371
+ if column = rename[fk.options[:column]]
372
+ fk.options[:column] = column
373
+ end
374
+ to_table = strip_table_name_prefix_and_suffix(fk.to_table)
375
+ definition.foreign_key(to_table, fk.options)
376
+ end
377
+
378
+ yield definition if block_given?
379
+ end
380
+
381
+ transaction do
382
+ disable_referential_integrity do
383
+ move_table(table_name, altered_table_name, options.merge(temporary: true))
384
+ move_table(altered_table_name, table_name, &caller)
385
+ end
386
+ end
387
+ end
388
+
389
+ def move_table(from, to, options = {}, &block)
390
+ copy_table(from, to, options, &block)
391
+ drop_table(from)
392
+ end
393
+
394
+ def copy_table(from, to, options = {})
395
+ from_primary_key = primary_key(from)
396
+ options[:id] = false
397
+ create_table(to, options) do |definition|
398
+ @definition = definition
399
+ if from_primary_key.is_a?(Array)
400
+ @definition.primary_keys from_primary_key
401
+ end
402
+ columns(from).each do |column|
403
+ column_name = options[:rename] ?
404
+ (options[:rename][column.name] ||
405
+ options[:rename][column.name.to_sym] ||
406
+ column.name) : column.name
407
+
408
+ @definition.column(column_name, column.type,
409
+ limit: column.limit, default: column.default,
410
+ precision: column.precision, scale: column.scale,
411
+ null: column.null, collation: column.collation,
412
+ primary_key: column_name == from_primary_key
413
+ )
414
+ end
415
+
416
+ yield @definition if block_given?
417
+ end
418
+ copy_table_indexes(from, to, options[:rename] || {})
419
+ copy_table_contents(from, to,
420
+ @definition.columns.map(&:name),
421
+ options[:rename] || {})
422
+ end
423
+
424
+ def copy_table_indexes(from, to, rename = {})
425
+ indexes(from).each do |index|
426
+ name = index.name
427
+ if to == "a#{from}"
428
+ name = "t#{name}"
429
+ elsif from == "a#{to}"
430
+ name = name[1..-1]
431
+ end
432
+
433
+ columns = index.columns
434
+ if columns.is_a?(Array)
435
+ to_column_names = columns(to).map(&:name)
436
+ columns = columns.map { |c| rename[c] || c }.select do |column|
437
+ to_column_names.include?(column)
438
+ end
439
+ end
440
+
441
+ unless columns.empty?
442
+ # index name can't be the same
443
+ opts = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
444
+ opts[:unique] = true if index.unique
445
+ opts[:where] = index.where if index.where
446
+ add_index(to, columns, opts)
447
+ end
448
+ end
449
+ end
450
+
451
+ def copy_table_contents(from, to, columns, rename = {})
452
+ column_mappings = Hash[columns.map { |name| [name, name] }]
453
+ rename.each { |a| column_mappings[a.last] = a.first }
454
+ from_columns = columns(from).collect(&:name)
455
+ columns = columns.find_all { |col| from_columns.include?(column_mappings[col]) }
456
+ from_columns_to_copy = columns.map { |col| column_mappings[col] }
457
+ quoted_columns = columns.map { |col| quote_column_name(col) } * ","
458
+ quoted_from_columns = from_columns_to_copy.map { |col| quote_column_name(col) } * ","
459
+
460
+ exec_query("INSERT INTO #{quote_table_name(to)} (#{quoted_columns})
461
+ SELECT #{quoted_from_columns} FROM #{quote_table_name(from)}")
462
+ end
463
+
464
+ def translate_exception(exception, message:, sql:, binds:)
465
+ case exception.message
466
+ # SQLite 3.8.2 returns a newly formatted error message:
467
+ # UNIQUE constraint failed: *table_name*.*column_name*
468
+ # Older versions of SQLite return:
469
+ # column *column_name* is not unique
470
+ when /column(s)? .* (is|are) not unique/, /UNIQUE constraint failed: .*/
471
+ RecordNotUnique.new(message, sql: sql, binds: binds)
472
+ when /.* may not be NULL/, /NOT NULL constraint failed: .*/
473
+ NotNullViolation.new(message, sql: sql, binds: binds)
474
+ when /FOREIGN KEY constraint failed/i
475
+ InvalidForeignKey.new(message, sql: sql, binds: binds)
476
+ else
477
+ super
478
+ end
479
+ end
480
+
481
+ COLLATE_REGEX = /.*\"(\w+)\".*collate\s+\"(\w+)\".*/i.freeze
482
+
483
+ def table_structure_with_collation(table_name, basic_structure)
484
+ collation_hash = {}
485
+ sql = <<~SQL
486
+ SELECT sql FROM
487
+ (SELECT * FROM sqlite_master UNION ALL
488
+ SELECT * FROM sqlite_temp_master)
489
+ WHERE type = 'table' AND name = #{quote(table_name)}
490
+ SQL
491
+
492
+ # Result will have following sample string
493
+ # CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
494
+ # "password_digest" varchar COLLATE "NOCASE");
495
+ result = exec_query(sql, "SCHEMA").first
496
+
497
+ if result
498
+ # Splitting with left parentheses and discarding the first part will return all
499
+ # columns separated with comma(,).
500
+ columns_string = result["sql"].split("(", 2).last
501
+
502
+ columns_string.split(",").each do |column_string|
503
+ # This regex will match the column name and collation type and will save
504
+ # the value in $1 and $2 respectively.
505
+ collation_hash[$1] = $2 if COLLATE_REGEX =~ column_string
506
+ end
507
+
508
+ basic_structure.map! do |column|
509
+ column_name = column["name"]
510
+
511
+ if collation_hash.has_key? column_name
512
+ column["collation"] = collation_hash[column_name]
513
+ end
514
+
515
+ column
516
+ end
517
+ else
518
+ basic_structure.to_a
519
+ end
520
+ end
521
+
522
+ def arel_visitor
523
+ Arel::Visitors::SQLite.new(self)
524
+ end
525
+
526
+ def build_statement_pool
527
+ StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
528
+ end
529
+
530
+ def connect
531
+ @connection = ::SQLite3::Database.new(
532
+ @config[:database].to_s,
533
+ @config.merge(results_as_hash: true)
534
+ )
535
+ configure_connection
536
+ end
537
+
538
+ def configure_connection
539
+ @connection.busy_timeout(self.class.type_cast_config_to_integer(@config[:timeout])) if @config[:timeout]
540
+
541
+ execute("PRAGMA foreign_keys = ON", "SCHEMA")
542
+ end
543
+
544
+ class SQLite3Integer < Type::Integer # :nodoc:
545
+ private
546
+ def _limit
547
+ # INTEGER storage class can be stored 8 bytes value.
548
+ # See https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes
549
+ limit || 8
550
+ end
551
+ end
552
+
553
+ ActiveRecord::Type.register(:integer, SQLite3Integer, adapter: :sqlite3)
53
554
  end
555
+ ActiveSupport.run_load_hooks(:active_record_sqlite3adapter, SQLite3Adapter)
54
556
  end
55
557
  end
@@ -1,40 +1,61 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module ConnectionAdapters
3
- class StatementPool
5
+ class StatementPool # :nodoc:
4
6
  include Enumerable
5
7
 
6
- def initialize(connection, max = 1000)
7
- @connection = connection
8
- @max = max
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
9
13
  end
10
14
 
11
- def each
12
- raise NotImplementedError
15
+ def each(&block)
16
+ cache.each(&block)
13
17
  end
14
18
 
15
19
  def key?(key)
16
- raise NotImplementedError
20
+ cache.key?(key)
17
21
  end
18
22
 
19
23
  def [](key)
20
- raise NotImplementedError
24
+ cache[key]
21
25
  end
22
26
 
23
27
  def length
24
- raise NotImplementedError
28
+ cache.length
25
29
  end
26
30
 
27
- def []=(sql, key)
28
- raise NotImplementedError
31
+ def []=(sql, stmt)
32
+ while @statement_limit <= cache.size
33
+ dealloc(cache.shift.last)
34
+ end
35
+ cache[sql] = stmt
29
36
  end
30
37
 
31
38
  def clear
32
- raise NotImplementedError
39
+ cache.each_value do |stmt|
40
+ dealloc stmt
41
+ end
42
+ cache.clear
33
43
  end
34
44
 
35
45
  def delete(key)
36
- raise NotImplementedError
46
+ dealloc cache[key]
47
+ cache.delete(key)
37
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
38
59
  end
39
60
  end
40
61
  end