activerecord 5.0.7.2 → 5.1.0.beta1

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 (216) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +389 -2252
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/examples/performance.rb +28 -28
  6. data/examples/simple.rb +3 -3
  7. data/lib/active_record.rb +20 -20
  8. data/lib/active_record/aggregations.rb +244 -244
  9. data/lib/active_record/association_relation.rb +5 -5
  10. data/lib/active_record/associations.rb +1579 -1569
  11. data/lib/active_record/associations/alias_tracker.rb +1 -1
  12. data/lib/active_record/associations/association.rb +23 -15
  13. data/lib/active_record/associations/association_scope.rb +83 -81
  14. data/lib/active_record/associations/belongs_to_association.rb +0 -1
  15. data/lib/active_record/associations/builder/belongs_to.rb +16 -14
  16. data/lib/active_record/associations/builder/collection_association.rb +1 -2
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +27 -27
  18. data/lib/active_record/associations/collection_association.rb +74 -241
  19. data/lib/active_record/associations/collection_proxy.rb +144 -70
  20. data/lib/active_record/associations/has_many_association.rb +15 -19
  21. data/lib/active_record/associations/has_many_through_association.rb +12 -5
  22. data/lib/active_record/associations/has_one_association.rb +22 -28
  23. data/lib/active_record/associations/has_one_through_association.rb +5 -1
  24. data/lib/active_record/associations/join_dependency.rb +117 -115
  25. data/lib/active_record/associations/join_dependency/join_association.rb +16 -13
  26. data/lib/active_record/associations/join_dependency/join_base.rb +1 -1
  27. data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
  28. data/lib/active_record/associations/preloader.rb +94 -94
  29. data/lib/active_record/associations/preloader/association.rb +87 -64
  30. data/lib/active_record/associations/preloader/belongs_to.rb +0 -2
  31. data/lib/active_record/associations/preloader/collection_association.rb +6 -6
  32. data/lib/active_record/associations/preloader/has_many.rb +0 -2
  33. data/lib/active_record/associations/preloader/singular_association.rb +6 -8
  34. data/lib/active_record/associations/preloader/through_association.rb +34 -41
  35. data/lib/active_record/associations/singular_association.rb +8 -25
  36. data/lib/active_record/associations/through_association.rb +3 -6
  37. data/lib/active_record/attribute.rb +98 -71
  38. data/lib/active_record/attribute/user_provided_default.rb +4 -2
  39. data/lib/active_record/attribute_assignment.rb +61 -61
  40. data/lib/active_record/attribute_decorators.rb +35 -13
  41. data/lib/active_record/attribute_methods.rb +56 -65
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -7
  43. data/lib/active_record/attribute_methods/dirty.rb +216 -34
  44. data/lib/active_record/attribute_methods/primary_key.rb +78 -73
  45. data/lib/active_record/attribute_methods/read.rb +39 -35
  46. data/lib/active_record/attribute_methods/serialization.rb +7 -7
  47. data/lib/active_record/attribute_methods/time_zone_conversion.rb +35 -58
  48. data/lib/active_record/attribute_methods/write.rb +36 -30
  49. data/lib/active_record/attribute_mutation_tracker.rb +53 -10
  50. data/lib/active_record/attribute_set.rb +9 -6
  51. data/lib/active_record/attribute_set/builder.rb +41 -49
  52. data/lib/active_record/attribute_set/yaml_encoder.rb +41 -0
  53. data/lib/active_record/attributes.rb +21 -21
  54. data/lib/active_record/autosave_association.rb +13 -13
  55. data/lib/active_record/base.rb +24 -22
  56. data/lib/active_record/callbacks.rb +52 -14
  57. data/lib/active_record/coders/yaml_column.rb +9 -11
  58. data/lib/active_record/collection_cache_key.rb +6 -17
  59. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +320 -278
  60. data/lib/active_record/connection_adapters/abstract/database_limits.rb +1 -3
  61. data/lib/active_record/connection_adapters/abstract/database_statements.rb +22 -34
  62. data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -27
  63. data/lib/active_record/connection_adapters/abstract/quoting.rb +44 -57
  64. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +9 -19
  65. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +78 -79
  66. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +53 -41
  67. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +99 -93
  68. data/lib/active_record/connection_adapters/abstract/transaction.rb +1 -5
  69. data/lib/active_record/connection_adapters/abstract_adapter.rb +156 -128
  70. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +424 -382
  71. data/lib/active_record/connection_adapters/column.rb +27 -5
  72. data/lib/active_record/connection_adapters/connection_specification.rb +128 -118
  73. data/lib/active_record/connection_adapters/mysql/column.rb +6 -31
  74. data/lib/active_record/connection_adapters/mysql/database_statements.rb +45 -43
  75. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +22 -22
  76. data/lib/active_record/connection_adapters/mysql/quoting.rb +6 -12
  77. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +49 -45
  78. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +16 -19
  79. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +49 -31
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +5 -6
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +24 -26
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +1 -28
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +46 -35
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +3 -3
  85. data/lib/active_record/connection_adapters/postgresql/oid.rb +22 -21
  86. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +9 -9
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +5 -3
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
  91. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +3 -3
  92. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +16 -16
  93. data/lib/active_record/connection_adapters/postgresql/oid/{rails_5_1_point.rb → legacy_point.rb} +9 -16
  94. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  95. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +13 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +28 -8
  97. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +28 -30
  98. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -1
  99. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +51 -51
  100. data/lib/active_record/connection_adapters/postgresql/quoting.rb +38 -36
  101. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +15 -0
  102. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +37 -24
  103. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +19 -23
  104. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +161 -170
  105. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +4 -4
  106. data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -7
  107. data/lib/active_record/connection_adapters/postgresql_adapter.rb +179 -152
  108. data/lib/active_record/connection_adapters/schema_cache.rb +16 -7
  109. data/lib/active_record/connection_adapters/sql_type_metadata.rb +3 -3
  110. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +1 -1
  111. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +16 -20
  112. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +1 -8
  113. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +28 -0
  114. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +17 -0
  115. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +187 -130
  116. data/lib/active_record/connection_adapters/statement_pool.rb +7 -7
  117. data/lib/active_record/connection_handling.rb +14 -26
  118. data/lib/active_record/core.rb +110 -93
  119. data/lib/active_record/counter_cache.rb +62 -13
  120. data/lib/active_record/define_callbacks.rb +20 -0
  121. data/lib/active_record/dynamic_matchers.rb +80 -79
  122. data/lib/active_record/enum.rb +8 -6
  123. data/lib/active_record/errors.rb +58 -15
  124. data/lib/active_record/explain.rb +1 -2
  125. data/lib/active_record/explain_registry.rb +1 -1
  126. data/lib/active_record/explain_subscriber.rb +7 -4
  127. data/lib/active_record/fixture_set/file.rb +11 -8
  128. data/lib/active_record/fixtures.rb +66 -53
  129. data/lib/active_record/gem_version.rb +3 -3
  130. data/lib/active_record/inheritance.rb +93 -79
  131. data/lib/active_record/integration.rb +7 -7
  132. data/lib/active_record/internal_metadata.rb +3 -16
  133. data/lib/active_record/legacy_yaml_adapter.rb +1 -1
  134. data/lib/active_record/locking/optimistic.rb +64 -56
  135. data/lib/active_record/locking/pessimistic.rb +10 -1
  136. data/lib/active_record/log_subscriber.rb +29 -29
  137. data/lib/active_record/migration.rb +155 -172
  138. data/lib/active_record/migration/command_recorder.rb +94 -94
  139. data/lib/active_record/migration/compatibility.rb +76 -37
  140. data/lib/active_record/migration/join_table.rb +6 -6
  141. data/lib/active_record/model_schema.rb +85 -119
  142. data/lib/active_record/nested_attributes.rb +200 -199
  143. data/lib/active_record/null_relation.rb +10 -33
  144. data/lib/active_record/persistence.rb +45 -38
  145. data/lib/active_record/query_cache.rb +4 -8
  146. data/lib/active_record/querying.rb +2 -3
  147. data/lib/active_record/railtie.rb +16 -17
  148. data/lib/active_record/railties/controller_runtime.rb +6 -2
  149. data/lib/active_record/railties/databases.rake +125 -140
  150. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  151. data/lib/active_record/readonly_attributes.rb +2 -2
  152. data/lib/active_record/reflection.rb +79 -96
  153. data/lib/active_record/relation.rb +72 -115
  154. data/lib/active_record/relation/batches.rb +87 -58
  155. data/lib/active_record/relation/batches/batch_enumerator.rb +1 -1
  156. data/lib/active_record/relation/calculations.rb +154 -160
  157. data/lib/active_record/relation/delegation.rb +30 -29
  158. data/lib/active_record/relation/finder_methods.rb +195 -226
  159. data/lib/active_record/relation/merger.rb +58 -62
  160. data/lib/active_record/relation/predicate_builder.rb +92 -89
  161. data/lib/active_record/relation/predicate_builder/array_handler.rb +7 -5
  162. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +23 -23
  163. data/lib/active_record/relation/predicate_builder/base_handler.rb +3 -1
  164. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +0 -8
  165. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +12 -10
  166. data/lib/active_record/relation/predicate_builder/range_handler.rb +0 -8
  167. data/lib/active_record/relation/query_attribute.rb +1 -1
  168. data/lib/active_record/relation/query_methods.rb +247 -295
  169. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  170. data/lib/active_record/relation/spawn_methods.rb +4 -5
  171. data/lib/active_record/relation/where_clause.rb +79 -65
  172. data/lib/active_record/relation/where_clause_factory.rb +47 -8
  173. data/lib/active_record/result.rb +29 -31
  174. data/lib/active_record/runtime_registry.rb +3 -3
  175. data/lib/active_record/sanitization.rb +182 -197
  176. data/lib/active_record/schema.rb +3 -3
  177. data/lib/active_record/schema_dumper.rb +14 -37
  178. data/lib/active_record/schema_migration.rb +3 -3
  179. data/lib/active_record/scoping.rb +9 -10
  180. data/lib/active_record/scoping/default.rb +87 -91
  181. data/lib/active_record/scoping/named.rb +16 -28
  182. data/lib/active_record/secure_token.rb +2 -2
  183. data/lib/active_record/statement_cache.rb +13 -15
  184. data/lib/active_record/store.rb +31 -32
  185. data/lib/active_record/suppressor.rb +2 -1
  186. data/lib/active_record/table_metadata.rb +9 -5
  187. data/lib/active_record/tasks/database_tasks.rb +72 -65
  188. data/lib/active_record/tasks/mysql_database_tasks.rb +75 -72
  189. data/lib/active_record/tasks/postgresql_database_tasks.rb +53 -48
  190. data/lib/active_record/tasks/sqlite_database_tasks.rb +18 -16
  191. data/lib/active_record/timestamp.rb +39 -25
  192. data/lib/active_record/touch_later.rb +1 -2
  193. data/lib/active_record/transactions.rb +98 -110
  194. data/lib/active_record/type.rb +17 -13
  195. data/lib/active_record/type/adapter_specific_registry.rb +46 -42
  196. data/lib/active_record/type/decimal_without_scale.rb +9 -0
  197. data/lib/active_record/type/hash_lookup_type_map.rb +3 -3
  198. data/lib/active_record/type/serialized.rb +8 -8
  199. data/lib/active_record/type/text.rb +9 -0
  200. data/lib/active_record/type/time.rb +0 -1
  201. data/lib/active_record/type/type_map.rb +11 -15
  202. data/lib/active_record/type/unsigned_integer.rb +15 -0
  203. data/lib/active_record/type_caster.rb +2 -2
  204. data/lib/active_record/type_caster/connection.rb +8 -6
  205. data/lib/active_record/type_caster/map.rb +3 -1
  206. data/lib/active_record/validations.rb +4 -4
  207. data/lib/active_record/validations/associated.rb +1 -1
  208. data/lib/active_record/validations/presence.rb +2 -2
  209. data/lib/active_record/validations/uniqueness.rb +8 -39
  210. data/lib/active_record/version.rb +1 -1
  211. data/lib/rails/generators/active_record.rb +4 -4
  212. data/lib/rails/generators/active_record/migration.rb +2 -2
  213. data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -34
  214. data/lib/rails/generators/active_record/model/model_generator.rb +9 -9
  215. metadata +22 -13
  216. data/lib/active_record/relation/predicate_builder/class_handler.rb +0 -27
@@ -21,6 +21,22 @@ module ActiveRecord
21
21
  @data_sources = @data_sources.dup
22
22
  end
23
23
 
24
+ def encode_with(coder)
25
+ coder["columns"] = @columns
26
+ coder["columns_hash"] = @columns_hash
27
+ coder["primary_keys"] = @primary_keys
28
+ coder["data_sources"] = @data_sources
29
+ coder["version"] = ActiveRecord::Migrator.current_version
30
+ end
31
+
32
+ def init_with(coder)
33
+ @columns = coder["columns"]
34
+ @columns_hash = coder["columns_hash"]
35
+ @primary_keys = coder["primary_keys"]
36
+ @data_sources = coder["data_sources"]
37
+ @version = coder["version"]
38
+ end
39
+
24
40
  def primary_keys(table_name)
25
41
  @primary_keys[table_name] ||= data_source_exists?(table_name) ? connection.primary_key(table_name) : nil
26
42
  end
@@ -32,9 +48,6 @@ module ActiveRecord
32
48
 
33
49
  @data_sources[name] = connection.data_source_exists?(name)
34
50
  end
35
- alias table_exists? data_source_exists?
36
- deprecate :table_exists? => "use #data_source_exists? instead"
37
-
38
51
 
39
52
  # Add internal cache for table with +table_name+.
40
53
  def add(table_name)
@@ -48,8 +61,6 @@ module ActiveRecord
48
61
  def data_sources(name)
49
62
  @data_sources[name]
50
63
  end
51
- alias tables data_sources
52
- deprecate :tables => "use #data_sources instead"
53
64
 
54
65
  # Get the columns for a table
55
66
  def columns(table_name)
@@ -84,8 +95,6 @@ module ActiveRecord
84
95
  @primary_keys.delete name
85
96
  @data_sources.delete name
86
97
  end
87
- alias clear_table_cache! clear_data_source_cache!
88
- deprecate :clear_table_cache! => "use #clear_data_source_cache! instead"
89
98
 
90
99
  def marshal_dump
91
100
  # if we get current version during initialization, it happens stack over flow.
@@ -24,9 +24,9 @@ module ActiveRecord
24
24
 
25
25
  protected
26
26
 
27
- def attributes_for_hash
28
- [self.class, sql_type, type, limit, precision, scale]
29
- end
27
+ def attributes_for_hash
28
+ [self.class, sql_type, type, limit, precision, scale]
29
+ end
30
30
  end
31
31
  end
32
32
  end
@@ -10,7 +10,7 @@ module ActiveRecord
10
10
  #
11
11
  def pp(result)
12
12
  result.rows.map do |row|
13
- row.join('|')
13
+ row.join("|")
14
14
  end.join("\n") + "\n"
15
15
  end
16
16
  end
@@ -11,37 +11,33 @@ module ActiveRecord
11
11
  end
12
12
 
13
13
  def quote_column_name(name)
14
- @quoted_column_names[name] ||= %Q("#{super.gsub('"', '""')}")
14
+ @quoted_column_names[name] ||= %Q("#{super.gsub('"', '""')}").freeze
15
15
  end
16
16
 
17
17
  def quoted_time(value)
18
- quoted_date(value).sub(/\A\d\d\d\d-\d\d-\d\d /, "2000-01-01 ")
18
+ quoted_date(value)
19
19
  end
20
20
 
21
- private
22
-
23
- def _quote(value)
24
- if value.is_a?(Type::Binary::Data)
25
- "x'#{value.hex}'"
26
- else
27
- super
28
- end
21
+ def quoted_binary(value)
22
+ "x'#{value.hex}'"
29
23
  end
30
24
 
31
- def _type_cast(value)
32
- case value
33
- when BigDecimal
34
- value.to_f
35
- when String
36
- if value.encoding == Encoding::ASCII_8BIT
37
- super(value.encode(Encoding::UTF_8))
25
+ private
26
+
27
+ def _type_cast(value)
28
+ case value
29
+ when BigDecimal
30
+ value.to_f
31
+ when String
32
+ if value.encoding == Encoding::ASCII_8BIT
33
+ super(value.encode(Encoding::UTF_8))
34
+ else
35
+ super
36
+ end
38
37
  else
39
38
  super
40
39
  end
41
- else
42
- super
43
40
  end
44
- end
45
41
  end
46
42
  end
47
43
  end
@@ -1,15 +1,8 @@
1
1
  module ActiveRecord
2
2
  module ConnectionAdapters
3
3
  module SQLite3
4
- class SchemaCreation < AbstractAdapter::SchemaCreation
4
+ class SchemaCreation < AbstractAdapter::SchemaCreation # :nodoc:
5
5
  private
6
-
7
- def column_options(o)
8
- options = super
9
- options[:null] = false if o.primary_key
10
- options
11
- end
12
-
13
6
  def add_column_options!(sql, options)
14
7
  if options[:collation]
15
8
  sql << " COLLATE \"#{options[:collation]}\""
@@ -0,0 +1,28 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module SQLite3
4
+ module ColumnMethods
5
+ def primary_key(name, type = :primary_key, **options)
6
+ if %i(integer bigint).include?(type) && (options.delete(:auto_increment) == true || !options.key?(:default))
7
+ type = :primary_key
8
+ end
9
+
10
+ super
11
+ end
12
+ end
13
+
14
+ class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
15
+ include ColumnMethods
16
+
17
+ def references(*args, **options)
18
+ super(*args, type: :integer, **options)
19
+ end
20
+ alias :belongs_to :references
21
+ end
22
+
23
+ class Table < ActiveRecord::ConnectionAdapters::Table
24
+ include ColumnMethods
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,17 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module SQLite3
4
+ module ColumnDumper # :nodoc:
5
+ private
6
+
7
+ def default_primary_key?(column)
8
+ schema_type(column) == :integer
9
+ end
10
+
11
+ def explicit_primary_key_default?(column)
12
+ column.bigint?
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,11 +1,13 @@
1
- require 'active_record/connection_adapters/abstract_adapter'
2
- require 'active_record/connection_adapters/statement_pool'
3
- require 'active_record/connection_adapters/sqlite3/explain_pretty_printer'
4
- require 'active_record/connection_adapters/sqlite3/quoting'
5
- require 'active_record/connection_adapters/sqlite3/schema_creation'
1
+ require "active_record/connection_adapters/abstract_adapter"
2
+ require "active_record/connection_adapters/statement_pool"
3
+ require "active_record/connection_adapters/sqlite3/explain_pretty_printer"
4
+ require "active_record/connection_adapters/sqlite3/quoting"
5
+ require "active_record/connection_adapters/sqlite3/schema_creation"
6
+ require "active_record/connection_adapters/sqlite3/schema_definitions"
7
+ require "active_record/connection_adapters/sqlite3/schema_dumper"
6
8
 
7
- gem 'sqlite3', '~> 1.3.6'
8
- require 'sqlite3'
9
+ gem "sqlite3", "~> 1.3.6"
10
+ require "sqlite3"
9
11
 
10
12
  module ActiveRecord
11
13
  module ConnectionHandling # :nodoc:
@@ -18,7 +20,7 @@ module ActiveRecord
18
20
  # Allow database path relative to Rails.root, but only if the database
19
21
  # path is not the special path that tells sqlite to build a database only
20
22
  # in memory.
21
- if ':memory:' != config[:database]
23
+ if ":memory:" != config[:database]
22
24
  config[:database] = File.expand_path(config[:database], Rails.root) if defined?(Rails.root)
23
25
  dirname = File.dirname(config[:database])
24
26
  Dir.mkdir(dirname) unless File.directory?(dirname)
@@ -26,7 +28,7 @@ module ActiveRecord
26
28
 
27
29
  db = SQLite3::Database.new(
28
30
  config[:database].to_s,
29
- :results_as_hash => true
31
+ results_as_hash: true
30
32
  )
31
33
 
32
34
  db.busy_timeout(ConnectionAdapters::SQLite3Adapter.type_cast_config_to_integer(config[:timeout])) if config[:timeout]
@@ -49,12 +51,13 @@ module ActiveRecord
49
51
  #
50
52
  # * <tt>:database</tt> - Path to the database file.
51
53
  class SQLite3Adapter < AbstractAdapter
52
- ADAPTER_NAME = 'SQLite'.freeze
54
+ ADAPTER_NAME = "SQLite".freeze
53
55
 
54
56
  include SQLite3::Quoting
57
+ include SQLite3::ColumnDumper
55
58
 
56
59
  NATIVE_DATABASE_TYPES = {
57
- primary_key: 'INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL',
60
+ primary_key: "INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL",
58
61
  string: { name: "varchar" },
59
62
  text: { name: "text" },
60
63
  integer: { name: "integer" },
@@ -70,9 +73,13 @@ module ActiveRecord
70
73
  class StatementPool < ConnectionAdapters::StatementPool
71
74
  private
72
75
 
73
- def dealloc(stmt)
74
- stmt[:stmt].close unless stmt[:stmt].closed?
75
- end
76
+ def dealloc(stmt)
77
+ stmt[:stmt].close unless stmt[:stmt].closed?
78
+ end
79
+ end
80
+
81
+ def update_table_definition(table_name, base) # :nodoc:
82
+ SQLite3::Table.new(table_name, base)
76
83
  end
77
84
 
78
85
  def schema_creation # :nodoc:
@@ -88,6 +95,8 @@ module ActiveRecord
88
95
 
89
96
  @active = nil
90
97
  @statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit]))
98
+
99
+ configure_connection
91
100
  end
92
101
 
93
102
  def supports_ddl_transactions?
@@ -99,7 +108,7 @@ module ActiveRecord
99
108
  end
100
109
 
101
110
  def supports_partial_index?
102
- sqlite_version >= '3.8.0'
111
+ sqlite_version >= "3.8.0"
103
112
  end
104
113
 
105
114
  # Returns true, since this connection adapter supports prepared statement
@@ -113,12 +122,12 @@ module ActiveRecord
113
122
  true
114
123
  end
115
124
 
116
- def supports_primary_key? #:nodoc:
125
+ def requires_reloading?
117
126
  true
118
127
  end
119
128
 
120
- def requires_reloading?
121
- true
129
+ def supports_foreign_keys_in_create?
130
+ sqlite_version >= "3.6.19"
122
131
  end
123
132
 
124
133
  def supports_views?
@@ -130,7 +139,7 @@ module ActiveRecord
130
139
  end
131
140
 
132
141
  def supports_multi_insert?
133
- sqlite_version >= '3.7.11'
142
+ sqlite_version >= "3.7.11"
134
143
  end
135
144
 
136
145
  def active?
@@ -159,7 +168,7 @@ module ActiveRecord
159
168
  end
160
169
 
161
170
  # Returns 62. SQLite supports index names up to 64
162
- # characters. The rest is used by rails internally to perform
171
+ # characters. The rest is used by Rails internally to perform
163
172
  # temporary rename operations
164
173
  def allowed_index_name_length
165
174
  index_name_length - 2
@@ -178,47 +187,62 @@ module ActiveRecord
178
187
  true
179
188
  end
180
189
 
190
+ # REFERENTIAL INTEGRITY ====================================
191
+
192
+ def disable_referential_integrity # :nodoc:
193
+ old = select_value("PRAGMA foreign_keys")
194
+
195
+ begin
196
+ execute("PRAGMA foreign_keys = OFF")
197
+ yield
198
+ ensure
199
+ execute("PRAGMA foreign_keys = #{old}")
200
+ end
201
+ end
202
+
181
203
  #--
182
204
  # DATABASE STATEMENTS ======================================
183
205
  #++
184
206
 
185
207
  def explain(arel, binds = [])
186
208
  sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
187
- SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', []))
209
+ SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", []))
188
210
  end
189
211
 
190
212
  def exec_query(sql, name = nil, binds = [], prepare: false)
191
213
  type_casted_binds = type_casted_binds(binds)
192
214
 
193
215
  log(sql, name, binds, type_casted_binds) do
194
- # Don't cache statements if they are not prepared
195
- unless prepare
196
- stmt = @connection.prepare(sql)
197
- begin
198
- cols = stmt.columns
199
- unless without_prepared_statement?(binds)
200
- stmt.bind_params(type_casted_binds)
216
+ ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
217
+ # Don't cache statements if they are not prepared
218
+ unless prepare
219
+ stmt = @connection.prepare(sql)
220
+ begin
221
+ cols = stmt.columns
222
+ unless without_prepared_statement?(binds)
223
+ stmt.bind_params(type_casted_binds)
224
+ end
225
+ records = stmt.to_a
226
+ ensure
227
+ stmt.close
201
228
  end
229
+ else
230
+ cache = @statements[sql] ||= {
231
+ stmt: @connection.prepare(sql)
232
+ }
233
+ stmt = cache[:stmt]
234
+ cols = cache[:cols] ||= stmt.columns
235
+ stmt.reset!
236
+ stmt.bind_params(type_casted_binds)
202
237
  records = stmt.to_a
203
- ensure
204
- stmt.close
205
238
  end
206
- else
207
- cache = @statements[sql] ||= {
208
- :stmt => @connection.prepare(sql)
209
- }
210
- stmt = cache[:stmt]
211
- cols = cache[:cols] ||= stmt.columns
212
- stmt.reset!
213
- stmt.bind_params(type_casted_binds)
214
- records = stmt.to_a
215
- end
216
239
 
217
- ActiveRecord::Result.new(cols, records)
240
+ ActiveRecord::Result.new(cols, records)
241
+ end
218
242
  end
219
243
  end
220
244
 
221
- def exec_delete(sql, name = 'SQL', binds = [])
245
+ def exec_delete(sql, name = "SQL", binds = [])
222
246
  exec_query(sql, name, binds)
223
247
  @connection.changes
224
248
  end
@@ -229,64 +253,55 @@ module ActiveRecord
229
253
  end
230
254
 
231
255
  def execute(sql, name = nil) #:nodoc:
232
- log(sql, name) { @connection.execute(sql) }
256
+ log(sql, name) do
257
+ ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
258
+ @connection.execute(sql)
259
+ end
260
+ end
233
261
  end
234
262
 
235
263
  def begin_db_transaction #:nodoc:
236
- log('begin transaction',nil) { @connection.transaction }
264
+ log("begin transaction", nil) { @connection.transaction }
237
265
  end
238
266
 
239
267
  def commit_db_transaction #:nodoc:
240
- log('commit transaction',nil) { @connection.commit }
268
+ log("commit transaction", nil) { @connection.commit }
241
269
  end
242
270
 
243
271
  def exec_rollback_db_transaction #:nodoc:
244
- log('rollback transaction',nil) { @connection.rollback }
272
+ log("rollback transaction", nil) { @connection.rollback }
245
273
  end
246
274
 
247
275
  # SCHEMA STATEMENTS ========================================
248
276
 
249
- def tables(name = nil) # :nodoc:
250
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
251
- #tables currently returns both tables and views.
252
- This behavior is deprecated and will be changed with Rails 5.1 to only return tables.
253
- Use #data_sources instead.
254
- MSG
255
-
256
- if name
257
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
258
- Passing arguments to #tables is deprecated without replacement.
259
- MSG
260
- end
277
+ def tables # :nodoc:
278
+ select_values("SELECT name FROM sqlite_master WHERE type = 'table' AND name <> 'sqlite_sequence'", "SCHEMA")
279
+ end
261
280
 
262
- data_sources
281
+ def data_sources # :nodoc:
282
+ select_values("SELECT name FROM sqlite_master WHERE type IN ('table','view') AND name <> 'sqlite_sequence'", "SCHEMA")
263
283
  end
264
284
 
265
- def data_sources
266
- select_values("SELECT name FROM sqlite_master WHERE type IN ('table','view') AND name <> 'sqlite_sequence'", 'SCHEMA')
285
+ def views # :nodoc:
286
+ select_values("SELECT name FROM sqlite_master WHERE type = 'view' AND name <> 'sqlite_sequence'", "SCHEMA")
267
287
  end
268
288
 
269
- def table_exists?(table_name)
270
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
271
- #table_exists? currently checks both tables and views.
272
- This behavior is deprecated and will be changed with Rails 5.1 to only check tables.
273
- Use #data_source_exists? instead.
274
- MSG
289
+ def table_exists?(table_name) # :nodoc:
290
+ return false unless table_name.present?
291
+
292
+ sql = "SELECT name FROM sqlite_master WHERE type = 'table' AND name <> 'sqlite_sequence'"
293
+ sql << " AND name = #{quote(table_name)}"
275
294
 
276
- data_source_exists?(table_name)
295
+ select_values(sql, "SCHEMA").any?
277
296
  end
278
297
 
279
- def data_source_exists?(table_name)
298
+ def data_source_exists?(table_name) # :nodoc:
280
299
  return false unless table_name.present?
281
300
 
282
301
  sql = "SELECT name FROM sqlite_master WHERE type IN ('table','view') AND name <> 'sqlite_sequence'"
283
302
  sql << " AND name = #{quote(table_name)}"
284
303
 
285
- select_values(sql, 'SCHEMA').any?
286
- end
287
-
288
- def views # :nodoc:
289
- select_values("SELECT name FROM sqlite_master WHERE type = 'view' AND name <> 'sqlite_sequence'", 'SCHEMA')
304
+ select_values(sql, "SCHEMA").any?
290
305
  end
291
306
 
292
307
  def view_exists?(view_name) # :nodoc:
@@ -295,32 +310,34 @@ module ActiveRecord
295
310
  sql = "SELECT name FROM sqlite_master WHERE type = 'view' AND name <> 'sqlite_sequence'"
296
311
  sql << " AND name = #{quote(view_name)}"
297
312
 
298
- select_values(sql, 'SCHEMA').any?
313
+ select_values(sql, "SCHEMA").any?
299
314
  end
300
315
 
301
- # Returns an array of +Column+ objects for the table specified by +table_name+.
302
- def columns(table_name) # :nodoc:
303
- table_name = table_name.to_s
304
- table_structure(table_name).map do |field|
305
- case field["dflt_value"]
306
- when /^null$/i
307
- field["dflt_value"] = nil
308
- when /^'(.*)'$/m
309
- field["dflt_value"] = $1.gsub("''", "'")
310
- when /^"(.*)"$/m
311
- field["dflt_value"] = $1.gsub('""', '"')
312
- end
313
-
314
- collation = field['collation']
315
- sql_type = field['type']
316
- type_metadata = fetch_type_metadata(sql_type)
317
- new_column(field['name'], field['dflt_value'], type_metadata, field['notnull'].to_i == 0, table_name, nil, collation)
316
+ def new_column_from_field(table_name, field) # :nondoc:
317
+ case field["dflt_value"]
318
+ when /^null$/i
319
+ field["dflt_value"] = nil
320
+ when /^'(.*)'$/m
321
+ field["dflt_value"] = $1.gsub("''", "'")
322
+ when /^"(.*)"$/m
323
+ field["dflt_value"] = $1.gsub('""', '"')
318
324
  end
325
+
326
+ collation = field["collation"]
327
+ sql_type = field["type"]
328
+ type_metadata = fetch_type_metadata(sql_type)
329
+ new_column(field["name"], field["dflt_value"], type_metadata, field["notnull"].to_i == 0, table_name, nil, collation)
319
330
  end
320
331
 
321
332
  # Returns an array of indexes for the given table.
322
333
  def indexes(table_name, name = nil) #:nodoc:
323
- exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", 'SCHEMA').map do |row|
334
+ if name
335
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
336
+ Passing name to #indexes is deprecated without replacement.
337
+ MSG
338
+ end
339
+
340
+ exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", "SCHEMA").map do |row|
324
341
  sql = <<-SQL
325
342
  SELECT sql
326
343
  FROM sqlite_master
@@ -330,22 +347,22 @@ module ActiveRecord
330
347
  FROM sqlite_temp_master
331
348
  WHERE name=#{quote(row['name'])} AND type='index'
332
349
  SQL
333
- index_sql = exec_query(sql).first['sql']
350
+ index_sql = exec_query(sql).first["sql"]
334
351
  match = /\sWHERE\s+(.+)$/i.match(index_sql)
335
352
  where = match[1] if match
336
353
  IndexDefinition.new(
337
354
  table_name,
338
- row['name'],
339
- row['unique'] != 0,
355
+ row["name"],
356
+ row["unique"] != 0,
340
357
  exec_query("PRAGMA index_info('#{row['name']}')", "SCHEMA").map { |col|
341
- col['name']
358
+ col["name"]
342
359
  }, nil, nil, where)
343
360
  end
344
361
  end
345
362
 
346
363
  def primary_keys(table_name) # :nodoc:
347
- pks = table_structure(table_name).select { |f| f['pk'] > 0 }
348
- pks.sort_by { |f| f['pk'] }.map { |f| f['name'] }
364
+ pks = table_structure(table_name).select { |f| f["pk"] > 0 }
365
+ pks.sort_by { |f| f["pk"] }.map { |f| f["name"] }
349
366
  end
350
367
 
351
368
  def remove_index(table_name, options = {}) #:nodoc:
@@ -410,7 +427,7 @@ module ActiveRecord
410
427
  self.default = options[:default] if include_default
411
428
  self.null = options[:null] if options.include?(:null)
412
429
  self.precision = options[:precision] if options.include?(:precision)
413
- self.scale = options[:scale] if options.include?(:scale)
430
+ self.scale = options[:scale] if options.include?(:scale)
414
431
  self.collation = options[:collation] if options.include?(:collation)
415
432
  end
416
433
  end
@@ -418,35 +435,54 @@ module ActiveRecord
418
435
 
419
436
  def rename_column(table_name, column_name, new_column_name) #:nodoc:
420
437
  column = column_for(table_name, column_name)
421
- alter_table(table_name, rename: {column.name => new_column_name.to_s})
438
+ alter_table(table_name, rename: { column.name => new_column_name.to_s })
422
439
  rename_column_indexes(table_name, column.name, new_column_name)
423
440
  end
424
441
 
425
- protected
442
+ def add_reference(table_name, ref_name, **options) # :nodoc:
443
+ super(table_name, ref_name, type: :integer, **options)
444
+ end
445
+ alias :add_belongs_to :add_reference
446
+
447
+ def foreign_keys(table_name)
448
+ fk_info = select_all("PRAGMA foreign_key_list(#{quote(table_name)})", "SCHEMA")
449
+ fk_info.map do |row|
450
+ options = {
451
+ column: row["from"],
452
+ primary_key: row["to"],
453
+ on_delete: extract_foreign_key_action(row["on_delete"]),
454
+ on_update: extract_foreign_key_action(row["on_update"])
455
+ }
456
+ ForeignKeyDefinition.new(table_name, row["table"], options)
457
+ end
458
+ end
459
+
460
+ private
426
461
 
427
462
  def table_structure(table_name)
428
- structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", 'SCHEMA')
463
+ structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", "SCHEMA")
429
464
  raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
430
465
  table_structure_with_collation(table_name, structure)
431
466
  end
467
+ alias column_definitions table_structure
432
468
 
433
- def alter_table(table_name, options = {}) #:nodoc:
469
+ def alter_table(table_name, options = {})
434
470
  altered_table_name = "a#{table_name}"
435
- caller = lambda {|definition| yield definition if block_given?}
471
+ caller = lambda { |definition| yield definition if block_given? }
436
472
 
437
473
  transaction do
438
474
  move_table(table_name, altered_table_name,
439
- options.merge(:temporary => true))
475
+ options.merge(temporary: true))
440
476
  move_table(altered_table_name, table_name, &caller)
441
477
  end
442
478
  end
443
479
 
444
- def move_table(from, to, options = {}, &block) #:nodoc:
480
+ def move_table(from, to, options = {}, &block)
445
481
  copy_table(from, to, options, &block)
446
482
  drop_table(from)
447
483
  end
448
484
 
449
- def copy_table(from, to, options = {}) #:nodoc:
485
+ def copy_table(from, to, options = {})
450
486
  from_primary_key = primary_key(from)
451
487
  options[:id] = false
452
488
  create_table(to, options) do |definition|
@@ -460,9 +496,9 @@ module ActiveRecord
460
496
  next if column_name == from_primary_key
461
497
 
462
498
  @definition.column(column_name, column.type,
463
- :limit => column.limit, :default => column.default,
464
- :precision => column.precision, :scale => column.scale,
465
- :null => column.null, collation: column.collation)
499
+ limit: column.limit, default: column.default,
500
+ precision: column.precision, scale: column.scale,
501
+ null: column.null, collation: column.collation)
466
502
  end
467
503
  yield @definition if block_given?
468
504
  end
@@ -472,7 +508,7 @@ module ActiveRecord
472
508
  options[:rename] || {})
473
509
  end
474
510
 
475
- def copy_table_indexes(from, to, rename = {}) #:nodoc:
511
+ def copy_table_indexes(from, to, rename = {})
476
512
  indexes(from).each do |index|
477
513
  name = index.name
478
514
  if to == "a#{from}"
@@ -482,7 +518,7 @@ module ActiveRecord
482
518
  end
483
519
 
484
520
  to_column_names = columns(to).map(&:name)
485
- columns = index.columns.map {|c| rename[c] || c }.select do |column|
521
+ columns = index.columns.map { |c| rename[c] || c }.select do |column|
486
522
  to_column_names.include?(column)
487
523
  end
488
524
 
@@ -495,21 +531,21 @@ module ActiveRecord
495
531
  end
496
532
  end
497
533
 
498
- def copy_table_contents(from, to, columns, rename = {}) #:nodoc:
499
- column_mappings = Hash[columns.map {|name| [name, name]}]
534
+ def copy_table_contents(from, to, columns, rename = {})
535
+ column_mappings = Hash[columns.map { |name| [name, name] }]
500
536
  rename.each { |a| column_mappings[a.last] = a.first }
501
537
  from_columns = columns(from).collect(&:name)
502
- columns = columns.find_all{|col| from_columns.include?(column_mappings[col])}
538
+ columns = columns.find_all { |col| from_columns.include?(column_mappings[col]) }
503
539
  from_columns_to_copy = columns.map { |col| column_mappings[col] }
504
- quoted_columns = columns.map { |col| quote_column_name(col) } * ','
505
- quoted_from_columns = from_columns_to_copy.map { |col| quote_column_name(col) } * ','
540
+ quoted_columns = columns.map { |col| quote_column_name(col) } * ","
541
+ quoted_from_columns = from_columns_to_copy.map { |col| quote_column_name(col) } * ","
506
542
 
507
543
  exec_query("INSERT INTO #{quote_table_name(to)} (#{quoted_columns})
508
544
  SELECT #{quoted_from_columns} FROM #{quote_table_name(from)}")
509
545
  end
510
546
 
511
547
  def sqlite_version
512
- @sqlite_version ||= SQLite3Adapter::Version.new(select_value('select sqlite_version(*)'))
548
+ @sqlite_version ||= SQLite3Adapter::Version.new(select_value("select sqlite_version(*)"))
513
549
  end
514
550
 
515
551
  def translate_exception(exception, message)
@@ -520,42 +556,47 @@ module ActiveRecord
520
556
  # column *column_name* is not unique
521
557
  when /column(s)? .* (is|are) not unique/, /UNIQUE constraint failed: .*/
522
558
  RecordNotUnique.new(message)
559
+ when /.* may not be NULL/, /NOT NULL constraint failed: .*/
560
+ NotNullViolation.new(message)
561
+ when /FOREIGN KEY constraint failed/i
562
+ InvalidForeignKey.new(message)
523
563
  else
524
564
  super
525
565
  end
526
566
  end
527
567
 
528
- private
529
568
  COLLATE_REGEX = /.*\"(\w+)\".*collate\s+\"(\w+)\".*/i.freeze
530
569
 
531
570
  def table_structure_with_collation(table_name, basic_structure)
532
571
  collation_hash = {}
533
- sql = "SELECT sql FROM
534
- (SELECT * FROM sqlite_master UNION ALL
535
- SELECT * FROM sqlite_temp_master)
536
- WHERE type='table' and name='#{ table_name }' \;"
572
+ sql = <<-SQL
573
+ SELECT sql FROM
574
+ (SELECT * FROM sqlite_master UNION ALL
575
+ SELECT * FROM sqlite_temp_master)
576
+ WHERE type = 'table' AND name = #{quote(table_name)}
577
+ SQL
537
578
 
538
579
  # Result will have following sample string
539
580
  # CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
540
581
  # "password_digest" varchar COLLATE "NOCASE");
541
- result = exec_query(sql, 'SCHEMA').first
582
+ result = exec_query(sql, "SCHEMA").first
542
583
 
543
584
  if result
544
585
  # Splitting with left parentheses and picking up last will return all
545
586
  # columns separated with comma(,).
546
- columns_string = result["sql"].split('(').last
587
+ columns_string = result["sql"].split("(").last
547
588
 
548
- columns_string.split(',').each do |column_string|
589
+ columns_string.split(",").each do |column_string|
549
590
  # This regex will match the column name and collation type and will save
550
591
  # the value in $1 and $2 respectively.
551
- collation_hash[$1] = $2 if (COLLATE_REGEX =~ column_string)
592
+ collation_hash[$1] = $2 if COLLATE_REGEX =~ column_string
552
593
  end
553
594
 
554
595
  basic_structure.map! do |column|
555
- column_name = column['name']
596
+ column_name = column["name"]
556
597
 
557
598
  if collation_hash.has_key? column_name
558
- column['collation'] = collation_hash[column_name]
599
+ column["collation"] = collation_hash[column_name]
559
600
  end
560
601
 
561
602
  column
@@ -564,6 +605,22 @@ module ActiveRecord
564
605
  basic_structure.to_hash
565
606
  end
566
607
  end
608
+
609
+ def create_table_definition(*args)
610
+ SQLite3::TableDefinition.new(*args)
611
+ end
612
+
613
+ def extract_foreign_key_action(specifier)
614
+ case specifier
615
+ when "CASCADE"; :cascade
616
+ when "SET NULL"; :nullify
617
+ when "RESTRICT"; :restrict
618
+ end
619
+ end
620
+
621
+ def configure_connection
622
+ execute("PRAGMA foreign_keys = ON", "SCHEMA")
623
+ end
567
624
  end
568
625
  end
569
626
  end