activerecord 3.1.10 → 4.2.11

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.

Potentially problematic release.


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

Files changed (237) hide show
  1. checksums.yaml +6 -6
  2. data/CHANGELOG.md +1837 -338
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +39 -43
  5. data/examples/performance.rb +51 -20
  6. data/examples/simple.rb +4 -4
  7. data/lib/active_record/aggregations.rb +57 -43
  8. data/lib/active_record/association_relation.rb +35 -0
  9. data/lib/active_record/associations/alias_tracker.rb +47 -39
  10. data/lib/active_record/associations/association.rb +71 -85
  11. data/lib/active_record/associations/association_scope.rb +138 -89
  12. data/lib/active_record/associations/belongs_to_association.rb +65 -25
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +9 -3
  14. data/lib/active_record/associations/builder/association.rb +125 -29
  15. data/lib/active_record/associations/builder/belongs_to.rb +91 -60
  16. data/lib/active_record/associations/builder/collection_association.rb +69 -49
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +113 -42
  18. data/lib/active_record/associations/builder/has_many.rb +8 -64
  19. data/lib/active_record/associations/builder/has_one.rb +12 -52
  20. data/lib/active_record/associations/builder/singular_association.rb +22 -29
  21. data/lib/active_record/associations/collection_association.rb +294 -187
  22. data/lib/active_record/associations/collection_proxy.rb +961 -94
  23. data/lib/active_record/associations/foreign_association.rb +11 -0
  24. data/lib/active_record/associations/has_many_association.rb +118 -23
  25. data/lib/active_record/associations/has_many_through_association.rb +115 -45
  26. data/lib/active_record/associations/has_one_association.rb +57 -24
  27. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  28. data/lib/active_record/associations/join_dependency/join_association.rb +76 -102
  29. data/lib/active_record/associations/join_dependency/join_base.rb +7 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +30 -37
  31. data/lib/active_record/associations/join_dependency.rb +230 -156
  32. data/lib/active_record/associations/preloader/association.rb +96 -55
  33. data/lib/active_record/associations/preloader/collection_association.rb +3 -3
  34. data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
  35. data/lib/active_record/associations/preloader/has_one.rb +1 -1
  36. data/lib/active_record/associations/preloader/singular_association.rb +3 -3
  37. data/lib/active_record/associations/preloader/through_association.rb +61 -32
  38. data/lib/active_record/associations/preloader.rb +113 -87
  39. data/lib/active_record/associations/singular_association.rb +29 -13
  40. data/lib/active_record/associations/through_association.rb +37 -19
  41. data/lib/active_record/associations.rb +505 -371
  42. data/lib/active_record/attribute.rb +163 -0
  43. data/lib/active_record/attribute_assignment.rb +212 -0
  44. data/lib/active_record/attribute_decorators.rb +66 -0
  45. data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
  46. data/lib/active_record/attribute_methods/dirty.rb +141 -51
  47. data/lib/active_record/attribute_methods/primary_key.rb +87 -36
  48. data/lib/active_record/attribute_methods/query.rb +5 -4
  49. data/lib/active_record/attribute_methods/read.rb +74 -117
  50. data/lib/active_record/attribute_methods/serialization.rb +70 -0
  51. data/lib/active_record/attribute_methods/time_zone_conversion.rb +49 -47
  52. data/lib/active_record/attribute_methods/write.rb +60 -21
  53. data/lib/active_record/attribute_methods.rb +409 -48
  54. data/lib/active_record/attribute_set/builder.rb +106 -0
  55. data/lib/active_record/attribute_set.rb +81 -0
  56. data/lib/active_record/attributes.rb +147 -0
  57. data/lib/active_record/autosave_association.rb +279 -232
  58. data/lib/active_record/base.rb +84 -1969
  59. data/lib/active_record/callbacks.rb +66 -28
  60. data/lib/active_record/coders/json.rb +13 -0
  61. data/lib/active_record/coders/yaml_column.rb +18 -21
  62. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +422 -243
  63. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  64. data/lib/active_record/connection_adapters/abstract/database_statements.rb +170 -194
  65. data/lib/active_record/connection_adapters/abstract/query_cache.rb +32 -19
  66. data/lib/active_record/connection_adapters/abstract/quoting.rb +79 -57
  67. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  68. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +125 -0
  69. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +273 -170
  70. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +50 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +731 -254
  72. data/lib/active_record/connection_adapters/abstract/transaction.rb +215 -0
  73. data/lib/active_record/connection_adapters/abstract_adapter.rb +339 -95
  74. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +946 -0
  75. data/lib/active_record/connection_adapters/column.rb +33 -221
  76. data/lib/active_record/connection_adapters/connection_specification.rb +275 -0
  77. data/lib/active_record/connection_adapters/mysql2_adapter.rb +140 -602
  78. data/lib/active_record/connection_adapters/mysql_adapter.rb +254 -756
  79. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +93 -0
  80. data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
  81. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +232 -0
  82. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +100 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  84. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +36 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +19 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +36 -0
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +108 -0
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
  110. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +596 -0
  112. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  113. data/lib/active_record/connection_adapters/postgresql_adapter.rb +445 -902
  114. data/lib/active_record/connection_adapters/schema_cache.rb +94 -0
  115. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +578 -25
  116. data/lib/active_record/connection_handling.rb +132 -0
  117. data/lib/active_record/core.rb +579 -0
  118. data/lib/active_record/counter_cache.rb +159 -102
  119. data/lib/active_record/dynamic_matchers.rb +140 -0
  120. data/lib/active_record/enum.rb +197 -0
  121. data/lib/active_record/errors.rb +102 -34
  122. data/lib/active_record/explain.rb +38 -0
  123. data/lib/active_record/explain_registry.rb +30 -0
  124. data/lib/active_record/explain_subscriber.rb +29 -0
  125. data/lib/active_record/fixture_set/file.rb +56 -0
  126. data/lib/active_record/fixtures.rb +318 -260
  127. data/lib/active_record/gem_version.rb +15 -0
  128. data/lib/active_record/inheritance.rb +247 -0
  129. data/lib/active_record/integration.rb +113 -0
  130. data/lib/active_record/legacy_yaml_adapter.rb +30 -0
  131. data/lib/active_record/locale/en.yml +8 -1
  132. data/lib/active_record/locking/optimistic.rb +80 -52
  133. data/lib/active_record/locking/pessimistic.rb +27 -5
  134. data/lib/active_record/log_subscriber.rb +25 -18
  135. data/lib/active_record/migration/command_recorder.rb +130 -38
  136. data/lib/active_record/migration/join_table.rb +15 -0
  137. data/lib/active_record/migration.rb +532 -201
  138. data/lib/active_record/model_schema.rb +342 -0
  139. data/lib/active_record/nested_attributes.rb +229 -139
  140. data/lib/active_record/no_touching.rb +52 -0
  141. data/lib/active_record/null_relation.rb +81 -0
  142. data/lib/active_record/persistence.rb +304 -99
  143. data/lib/active_record/query_cache.rb +25 -43
  144. data/lib/active_record/querying.rb +68 -0
  145. data/lib/active_record/railtie.rb +86 -45
  146. data/lib/active_record/railties/console_sandbox.rb +3 -4
  147. data/lib/active_record/railties/controller_runtime.rb +7 -4
  148. data/lib/active_record/railties/databases.rake +198 -377
  149. data/lib/active_record/railties/jdbcmysql_error.rb +2 -2
  150. data/lib/active_record/readonly_attributes.rb +23 -0
  151. data/lib/active_record/reflection.rb +516 -165
  152. data/lib/active_record/relation/batches.rb +96 -45
  153. data/lib/active_record/relation/calculations.rb +221 -144
  154. data/lib/active_record/relation/delegation.rb +140 -0
  155. data/lib/active_record/relation/finder_methods.rb +362 -243
  156. data/lib/active_record/relation/merger.rb +193 -0
  157. data/lib/active_record/relation/predicate_builder/array_handler.rb +48 -0
  158. data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
  159. data/lib/active_record/relation/predicate_builder.rb +135 -41
  160. data/lib/active_record/relation/query_methods.rb +982 -155
  161. data/lib/active_record/relation/spawn_methods.rb +50 -110
  162. data/lib/active_record/relation.rb +371 -180
  163. data/lib/active_record/result.rb +109 -12
  164. data/lib/active_record/runtime_registry.rb +22 -0
  165. data/lib/active_record/sanitization.rb +191 -0
  166. data/lib/active_record/schema.rb +19 -13
  167. data/lib/active_record/schema_dumper.rb +111 -61
  168. data/lib/active_record/schema_migration.rb +53 -0
  169. data/lib/active_record/scoping/default.rb +135 -0
  170. data/lib/active_record/scoping/named.rb +164 -0
  171. data/lib/active_record/scoping.rb +87 -0
  172. data/lib/active_record/serialization.rb +7 -45
  173. data/lib/active_record/serializers/xml_serializer.rb +14 -65
  174. data/lib/active_record/statement_cache.rb +111 -0
  175. data/lib/active_record/store.rb +205 -0
  176. data/lib/active_record/tasks/database_tasks.rb +299 -0
  177. data/lib/active_record/tasks/mysql_database_tasks.rb +159 -0
  178. data/lib/active_record/tasks/postgresql_database_tasks.rb +101 -0
  179. data/lib/active_record/tasks/sqlite_database_tasks.rb +55 -0
  180. data/lib/active_record/timestamp.rb +35 -14
  181. data/lib/active_record/transactions.rb +141 -74
  182. data/lib/active_record/translation.rb +22 -0
  183. data/lib/active_record/type/big_integer.rb +13 -0
  184. data/lib/active_record/type/binary.rb +50 -0
  185. data/lib/active_record/type/boolean.rb +31 -0
  186. data/lib/active_record/type/date.rb +50 -0
  187. data/lib/active_record/type/date_time.rb +54 -0
  188. data/lib/active_record/type/decimal.rb +64 -0
  189. data/lib/active_record/type/decimal_without_scale.rb +11 -0
  190. data/lib/active_record/type/decorator.rb +14 -0
  191. data/lib/active_record/type/float.rb +19 -0
  192. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  193. data/lib/active_record/type/integer.rb +59 -0
  194. data/lib/active_record/type/mutable.rb +16 -0
  195. data/lib/active_record/type/numeric.rb +36 -0
  196. data/lib/active_record/type/serialized.rb +62 -0
  197. data/lib/active_record/type/string.rb +40 -0
  198. data/lib/active_record/type/text.rb +11 -0
  199. data/lib/active_record/type/time.rb +26 -0
  200. data/lib/active_record/type/time_value.rb +38 -0
  201. data/lib/active_record/type/type_map.rb +64 -0
  202. data/lib/active_record/type/unsigned_integer.rb +15 -0
  203. data/lib/active_record/type/value.rb +110 -0
  204. data/lib/active_record/type.rb +23 -0
  205. data/lib/active_record/validations/associated.rb +27 -18
  206. data/lib/active_record/validations/presence.rb +67 -0
  207. data/lib/active_record/validations/uniqueness.rb +125 -66
  208. data/lib/active_record/validations.rb +37 -30
  209. data/lib/active_record/version.rb +5 -7
  210. data/lib/active_record.rb +80 -25
  211. data/lib/rails/generators/active_record/migration/migration_generator.rb +54 -9
  212. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +19 -0
  213. data/lib/rails/generators/active_record/migration/templates/migration.rb +25 -11
  214. data/lib/rails/generators/active_record/migration.rb +11 -8
  215. data/lib/rails/generators/active_record/model/model_generator.rb +17 -4
  216. data/lib/rails/generators/active_record/model/templates/model.rb +5 -2
  217. data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
  218. data/lib/rails/generators/active_record.rb +3 -11
  219. metadata +132 -53
  220. data/examples/associations.png +0 -0
  221. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -62
  222. data/lib/active_record/associations/join_helper.rb +0 -55
  223. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  224. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -135
  225. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -556
  226. data/lib/active_record/dynamic_finder_match.rb +0 -56
  227. data/lib/active_record/dynamic_scope_match.rb +0 -23
  228. data/lib/active_record/identity_map.rb +0 -163
  229. data/lib/active_record/named_scope.rb +0 -200
  230. data/lib/active_record/observer.rb +0 -121
  231. data/lib/active_record/session_store.rb +0 -358
  232. data/lib/active_record/test_case.rb +0 -69
  233. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -17
  234. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  235. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  236. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  237. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -16
@@ -1,556 +0,0 @@
1
- require 'active_record/connection_adapters/abstract_adapter'
2
- require 'active_support/core_ext/kernel/requires'
3
- require 'active_record/connection_adapters/statement_pool'
4
- require 'active_support/core_ext/string/encoding'
5
- require 'arel/visitors/bind_visitor'
6
-
7
- module ActiveRecord
8
- module ConnectionAdapters #:nodoc:
9
- class SQLiteColumn < Column #:nodoc:
10
- class << self
11
- def string_to_binary(value)
12
- value.gsub(/\0|\%/n) do |b|
13
- case b
14
- when "\0" then "%00"
15
- when "%" then "%25"
16
- end
17
- end
18
- end
19
-
20
- def binary_to_string(value)
21
- if value.respond_to?(:force_encoding) && value.encoding != Encoding::ASCII_8BIT
22
- value = value.force_encoding(Encoding::ASCII_8BIT)
23
- end
24
-
25
- value.gsub(/%00|%25/n) do |b|
26
- case b
27
- when "%00" then "\0"
28
- when "%25" then "%"
29
- end
30
- end
31
- end
32
- end
33
- end
34
-
35
- # The SQLite adapter works with both the 2.x and 3.x series of SQLite with the sqlite-ruby
36
- # drivers (available both as gems and from http://rubyforge.org/projects/sqlite-ruby/).
37
- #
38
- # Options:
39
- #
40
- # * <tt>:database</tt> - Path to the database file.
41
- class SQLiteAdapter < AbstractAdapter
42
- class Version
43
- include Comparable
44
-
45
- def initialize(version_string)
46
- @version = version_string.split('.').map { |v| v.to_i }
47
- end
48
-
49
- def <=>(version_string)
50
- @version <=> version_string.split('.').map { |v| v.to_i }
51
- end
52
- end
53
-
54
- class StatementPool < ConnectionAdapters::StatementPool
55
- def initialize(connection, max)
56
- super
57
- @cache = Hash.new { |h,pid| h[pid] = {} }
58
- end
59
-
60
- def each(&block); cache.each(&block); end
61
- def key?(key); cache.key?(key); end
62
- def [](key); cache[key]; end
63
- def length; cache.length; end
64
-
65
- def []=(sql, key)
66
- while @max <= cache.size
67
- dealloc(cache.shift.last[:stmt])
68
- end
69
- cache[sql] = key
70
- end
71
-
72
- def clear
73
- cache.values.each do |hash|
74
- dealloc hash[:stmt]
75
- end
76
- cache.clear
77
- end
78
-
79
- private
80
- def cache
81
- @cache[$$]
82
- end
83
-
84
- def dealloc(stmt)
85
- stmt.close unless stmt.closed?
86
- end
87
- end
88
-
89
- class BindSubstitution < Arel::Visitors::SQLite # :nodoc:
90
- include Arel::Visitors::BindVisitor
91
- end
92
-
93
- def initialize(connection, logger, config)
94
- super(connection, logger)
95
- @statements = StatementPool.new(@connection,
96
- config.fetch(:statement_limit) { 1000 })
97
- @config = config
98
- end
99
-
100
- def self.visitor_for(pool) # :nodoc:
101
- config = pool.spec.config
102
-
103
- if config.fetch(:prepared_statements) { true }
104
- Arel::Visitors::SQLite.new pool
105
- else
106
- BindSubstitution.new pool
107
- end
108
- end
109
-
110
- def adapter_name #:nodoc:
111
- 'SQLite'
112
- end
113
-
114
- # Returns true if SQLite version is '2.0.0' or greater, false otherwise.
115
- def supports_ddl_transactions?
116
- sqlite_version >= '2.0.0'
117
- end
118
-
119
- # Returns true if SQLite version is '3.6.8' or greater, false otherwise.
120
- def supports_savepoints?
121
- sqlite_version >= '3.6.8'
122
- end
123
-
124
- # Returns true, since this connection adapter supports prepared statement
125
- # caching.
126
- def supports_statement_cache?
127
- true
128
- end
129
-
130
- # Returns true, since this connection adapter supports migrations.
131
- def supports_migrations? #:nodoc:
132
- true
133
- end
134
-
135
- # Returns true.
136
- def supports_primary_key? #:nodoc:
137
- true
138
- end
139
-
140
- def requires_reloading?
141
- true
142
- end
143
-
144
- # Returns true if SQLite version is '3.1.6' or greater, false otherwise.
145
- def supports_add_column?
146
- sqlite_version >= '3.1.6'
147
- end
148
-
149
- # Disconnects from the database if already connected. Otherwise, this
150
- # method does nothing.
151
- def disconnect!
152
- super
153
- clear_cache!
154
- @connection.close rescue nil
155
- end
156
-
157
- # Clears the prepared statements cache.
158
- def clear_cache!
159
- @statements.clear
160
- end
161
-
162
- # Returns true if SQLite version is '3.2.6' or greater, false otherwise.
163
- def supports_count_distinct? #:nodoc:
164
- sqlite_version >= '3.2.6'
165
- end
166
-
167
- # Returns true if SQLite version is '3.1.0' or greater, false otherwise.
168
- def supports_autoincrement? #:nodoc:
169
- sqlite_version >= '3.1.0'
170
- end
171
-
172
- def native_database_types #:nodoc:
173
- {
174
- :primary_key => default_primary_key_type,
175
- :string => { :name => "varchar", :limit => 255 },
176
- :text => { :name => "text" },
177
- :integer => { :name => "integer" },
178
- :float => { :name => "float" },
179
- :decimal => { :name => "decimal" },
180
- :datetime => { :name => "datetime" },
181
- :timestamp => { :name => "datetime" },
182
- :time => { :name => "time" },
183
- :date => { :name => "date" },
184
- :binary => { :name => "blob" },
185
- :boolean => { :name => "boolean" }
186
- }
187
- end
188
-
189
-
190
- # QUOTING ==================================================
191
-
192
- def quote_string(s) #:nodoc:
193
- @connection.class.quote(s)
194
- end
195
-
196
- def quote_column_name(name) #:nodoc:
197
- %Q("#{name.to_s.gsub('"', '""')}")
198
- end
199
-
200
- # Quote date/time values for use in SQL input. Includes microseconds
201
- # if the value is a Time responding to usec.
202
- def quoted_date(value) #:nodoc:
203
- if value.respond_to?(:usec)
204
- "#{super}.#{sprintf("%06d", value.usec)}"
205
- else
206
- super
207
- end
208
- end
209
-
210
- if "<3".encoding_aware?
211
- def type_cast(value, column) # :nodoc:
212
- return value.to_f if BigDecimal === value
213
- return super unless String === value
214
- return super unless column && value
215
-
216
- value = super
217
- if column.type == :string && value.encoding == Encoding::ASCII_8BIT
218
- logger.error "Binary data inserted for `string` type on column `#{column.name}`" if logger
219
- value.encode! 'utf-8'
220
- end
221
- value
222
- end
223
- else
224
- def type_cast(value, column) # :nodoc:
225
- return super unless BigDecimal === value
226
-
227
- value.to_f
228
- end
229
- end
230
-
231
- # DATABASE STATEMENTS ======================================
232
-
233
- def exec_query(sql, name = nil, binds = [])
234
- log(sql, name, binds) do
235
-
236
- # Don't cache statements without bind values
237
- if binds.empty?
238
- stmt = @connection.prepare(sql)
239
- cols = stmt.columns
240
- records = stmt.to_a
241
- stmt.close
242
- stmt = records
243
- else
244
- cache = @statements[sql] ||= {
245
- :stmt => @connection.prepare(sql)
246
- }
247
- stmt = cache[:stmt]
248
- cols = cache[:cols] ||= stmt.columns
249
- stmt.reset!
250
- stmt.bind_params binds.map { |col, val|
251
- type_cast(val, col)
252
- }
253
- end
254
-
255
- ActiveRecord::Result.new(cols, stmt.to_a)
256
- end
257
- end
258
-
259
- def exec_delete(sql, name = 'SQL', binds = [])
260
- exec_query(sql, name, binds)
261
- @connection.changes
262
- end
263
- alias :exec_update :exec_delete
264
-
265
- def last_inserted_id(result)
266
- @connection.last_insert_row_id
267
- end
268
-
269
- def execute(sql, name = nil) #:nodoc:
270
- log(sql, name) { @connection.execute(sql) }
271
- end
272
-
273
- def update_sql(sql, name = nil) #:nodoc:
274
- super
275
- @connection.changes
276
- end
277
-
278
- def delete_sql(sql, name = nil) #:nodoc:
279
- sql += " WHERE 1=1" unless sql =~ /WHERE/i
280
- super sql, name
281
- end
282
-
283
- def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
284
- super
285
- id_value || @connection.last_insert_row_id
286
- end
287
- alias :create :insert_sql
288
-
289
- def select_rows(sql, name = nil)
290
- exec_query(sql, name).rows
291
- end
292
-
293
- def create_savepoint
294
- execute("SAVEPOINT #{current_savepoint_name}")
295
- end
296
-
297
- def rollback_to_savepoint
298
- execute("ROLLBACK TO SAVEPOINT #{current_savepoint_name}")
299
- end
300
-
301
- def release_savepoint
302
- execute("RELEASE SAVEPOINT #{current_savepoint_name}")
303
- end
304
-
305
- def begin_db_transaction #:nodoc:
306
- @connection.transaction
307
- end
308
-
309
- def commit_db_transaction #:nodoc:
310
- @connection.commit
311
- end
312
-
313
- def rollback_db_transaction #:nodoc:
314
- @connection.rollback
315
- end
316
-
317
- # SCHEMA STATEMENTS ========================================
318
-
319
- def tables(name = 'SCHEMA') #:nodoc:
320
- sql = <<-SQL
321
- SELECT name
322
- FROM sqlite_master
323
- WHERE type = 'table' AND NOT name = 'sqlite_sequence'
324
- SQL
325
-
326
- exec_query(sql, name).map do |row|
327
- row['name']
328
- end
329
- end
330
-
331
- # Returns an array of +SQLiteColumn+ objects for the table specified by +table_name+.
332
- def columns(table_name, name = nil) #:nodoc:
333
- table_structure(table_name).map do |field|
334
- case field["dflt_value"]
335
- when /^null$/i
336
- field["dflt_value"] = nil
337
- when /^'(.*)'$/
338
- field["dflt_value"] = $1.gsub(/''/, "'")
339
- when /^"(.*)"$/
340
- field["dflt_value"] = $1.gsub(/""/, '"')
341
- end
342
-
343
- SQLiteColumn.new(field['name'], field['dflt_value'], field['type'], field['notnull'].to_i == 0)
344
- end
345
- end
346
-
347
- # Returns an array of indexes for the given table.
348
- def indexes(table_name, name = nil) #:nodoc:
349
- exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", name).map do |row|
350
- IndexDefinition.new(
351
- table_name,
352
- row['name'],
353
- row['unique'] != 0,
354
- exec_query("PRAGMA index_info('#{row['name']}')").map { |col|
355
- col['name']
356
- })
357
- end
358
- end
359
-
360
- def primary_key(table_name) #:nodoc:
361
- column = table_structure(table_name).find { |field|
362
- field['pk'] == 1
363
- }
364
- column && column['name']
365
- end
366
-
367
- def remove_index!(table_name, index_name) #:nodoc:
368
- exec_query "DROP INDEX #{quote_column_name(index_name)}"
369
- end
370
-
371
- # Renames a table.
372
- #
373
- # Example:
374
- # rename_table('octopuses', 'octopi')
375
- def rename_table(name, new_name)
376
- exec_query "ALTER TABLE #{quote_table_name(name)} RENAME TO #{quote_table_name(new_name)}"
377
- end
378
-
379
- # See: http://www.sqlite.org/lang_altertable.html
380
- # SQLite has an additional restriction on the ALTER TABLE statement
381
- def valid_alter_table_options( type, options)
382
- type.to_sym != :primary_key
383
- end
384
-
385
- def add_column(table_name, column_name, type, options = {}) #:nodoc:
386
- if supports_add_column? && valid_alter_table_options( type, options )
387
- super(table_name, column_name, type, options)
388
- else
389
- alter_table(table_name) do |definition|
390
- definition.column(column_name, type, options)
391
- end
392
- end
393
- end
394
-
395
- def remove_column(table_name, *column_names) #:nodoc:
396
- raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.empty?
397
- column_names.flatten.each do |column_name|
398
- alter_table(table_name) do |definition|
399
- definition.columns.delete(definition[column_name])
400
- end
401
- end
402
- end
403
- alias :remove_columns :remove_column
404
-
405
- def change_column_default(table_name, column_name, default) #:nodoc:
406
- alter_table(table_name) do |definition|
407
- definition[column_name].default = default
408
- end
409
- end
410
-
411
- def change_column_null(table_name, column_name, null, default = nil)
412
- unless null || default.nil?
413
- exec_query("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
414
- end
415
- alter_table(table_name) do |definition|
416
- definition[column_name].null = null
417
- end
418
- end
419
-
420
- def change_column(table_name, column_name, type, options = {}) #:nodoc:
421
- alter_table(table_name) do |definition|
422
- include_default = options_include_default?(options)
423
- definition[column_name].instance_eval do
424
- self.type = type
425
- self.limit = options[:limit] if options.include?(:limit)
426
- self.default = options[:default] if include_default
427
- self.null = options[:null] if options.include?(:null)
428
- end
429
- end
430
- end
431
-
432
- def rename_column(table_name, column_name, new_column_name) #:nodoc:
433
- unless columns(table_name).detect{|c| c.name == column_name.to_s }
434
- raise ActiveRecord::ActiveRecordError, "Missing column #{table_name}.#{column_name}"
435
- end
436
- alter_table(table_name, :rename => {column_name.to_s => new_column_name.to_s})
437
- end
438
-
439
- def empty_insert_statement_value
440
- "VALUES(NULL)"
441
- end
442
-
443
- protected
444
- def select(sql, name = nil, binds = []) #:nodoc:
445
- exec_query(sql, name, binds).to_a
446
- end
447
-
448
- def table_structure(table_name)
449
- structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", 'SCHEMA').to_hash
450
- raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
451
- structure
452
- end
453
-
454
- def alter_table(table_name, options = {}) #:nodoc:
455
- altered_table_name = "altered_#{table_name}"
456
- caller = lambda {|definition| yield definition if block_given?}
457
-
458
- transaction do
459
- move_table(table_name, altered_table_name,
460
- options.merge(:temporary => true))
461
- move_table(altered_table_name, table_name, &caller)
462
- end
463
- end
464
-
465
- def move_table(from, to, options = {}, &block) #:nodoc:
466
- copy_table(from, to, options, &block)
467
- drop_table(from)
468
- end
469
-
470
- def copy_table(from, to, options = {}) #:nodoc:
471
- options = options.merge(:id => (!columns(from).detect{|c| c.name == 'id'}.nil? && 'id' == primary_key(from).to_s))
472
- create_table(to, options) do |definition|
473
- @definition = definition
474
- columns(from).each do |column|
475
- column_name = options[:rename] ?
476
- (options[:rename][column.name] ||
477
- options[:rename][column.name.to_sym] ||
478
- column.name) : column.name
479
-
480
- @definition.column(column_name, column.type,
481
- :limit => column.limit, :default => column.default,
482
- :null => column.null)
483
- end
484
- @definition.primary_key(primary_key(from)) if primary_key(from)
485
- yield @definition if block_given?
486
- end
487
-
488
- copy_table_indexes(from, to, options[:rename] || {})
489
- copy_table_contents(from, to,
490
- @definition.columns.map {|column| column.name},
491
- options[:rename] || {})
492
- end
493
-
494
- def copy_table_indexes(from, to, rename = {}) #:nodoc:
495
- indexes(from).each do |index|
496
- name = index.name
497
- if to == "altered_#{from}"
498
- name = "temp_#{name}"
499
- elsif from == "altered_#{to}"
500
- name = name[5..-1]
501
- end
502
-
503
- to_column_names = columns(to).map { |c| c.name }
504
- columns = index.columns.map {|c| rename[c] || c }.select do |column|
505
- to_column_names.include?(column)
506
- end
507
-
508
- unless columns.empty?
509
- # index name can't be the same
510
- opts = { :name => name.gsub(/_(#{from})_/, "_#{to}_") }
511
- opts[:unique] = true if index.unique
512
- add_index(to, columns, opts)
513
- end
514
- end
515
- end
516
-
517
- def copy_table_contents(from, to, columns, rename = {}) #:nodoc:
518
- column_mappings = Hash[columns.map {|name| [name, name]}]
519
- rename.each { |a| column_mappings[a.last] = a.first }
520
- from_columns = columns(from).collect {|col| col.name}
521
- columns = columns.find_all{|col| from_columns.include?(column_mappings[col])}
522
- quoted_columns = columns.map { |col| quote_column_name(col) } * ','
523
-
524
- quoted_to = quote_table_name(to)
525
- exec_query("SELECT * FROM #{quote_table_name(from)}").each do |row|
526
- sql = "INSERT INTO #{quoted_to} (#{quoted_columns}) VALUES ("
527
- sql << columns.map {|col| quote row[column_mappings[col]]} * ', '
528
- sql << ')'
529
- exec_query sql
530
- end
531
- end
532
-
533
- def sqlite_version
534
- @sqlite_version ||= SQLiteAdapter::Version.new(select_value('select sqlite_version(*)'))
535
- end
536
-
537
- def default_primary_key_type
538
- if supports_autoincrement?
539
- 'INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL'
540
- else
541
- 'INTEGER PRIMARY KEY NOT NULL'
542
- end
543
- end
544
-
545
- def translate_exception(exception, message)
546
- case exception.message
547
- when /column(s)? .* (is|are) not unique/
548
- RecordNotUnique.new(message, exception)
549
- else
550
- super
551
- end
552
- end
553
-
554
- end
555
- end
556
- end
@@ -1,56 +0,0 @@
1
- module ActiveRecord
2
-
3
- # = Active Record Dynamic Finder Match
4
- #
5
- # Refer to ActiveRecord::Base documentation for Dynamic attribute-based finders for detailed info
6
- #
7
- class DynamicFinderMatch
8
- def self.match(method)
9
- finder = :first
10
- bang = false
11
- instantiator = nil
12
-
13
- case method.to_s
14
- when /^find_(all_|last_)?by_([_a-zA-Z]\w*)$/
15
- finder = :last if $1 == 'last_'
16
- finder = :all if $1 == 'all_'
17
- names = $2
18
- when /^find_by_([_a-zA-Z]\w*)\!$/
19
- bang = true
20
- names = $1
21
- when /^find_or_(initialize|create)_by_([_a-zA-Z]\w*)$/
22
- instantiator = $1 == 'initialize' ? :new : :create
23
- names = $2
24
- else
25
- return nil
26
- end
27
-
28
- new(finder, instantiator, bang, names.split('_and_'))
29
- end
30
-
31
- def initialize(finder, instantiator, bang, attribute_names)
32
- @finder = finder
33
- @instantiator = instantiator
34
- @bang = bang
35
- @attribute_names = attribute_names
36
- end
37
-
38
- attr_reader :finder, :attribute_names, :instantiator
39
-
40
- def finder?
41
- @finder && !@instantiator
42
- end
43
-
44
- def instantiator?
45
- @finder == :first && @instantiator
46
- end
47
-
48
- def creator?
49
- @finder == :first && @instantiator == :create
50
- end
51
-
52
- def bang?
53
- @bang
54
- end
55
- end
56
- end
@@ -1,23 +0,0 @@
1
- module ActiveRecord
2
-
3
- # = Active Record Dynamic Scope Match
4
- #
5
- # Provides dynamic attribute-based scopes such as <tt>scoped_by_price(4.99)</tt>
6
- # if, for example, the <tt>Product</tt> has an attribute with that name. You can
7
- # chain more <tt>scoped_by_* </tt> methods after the other. It acts like a named
8
- # scope except that it's dynamic.
9
- class DynamicScopeMatch
10
- def self.match(method)
11
- return unless method.to_s =~ /^scoped_by_([_a-zA-Z]\w*)$/
12
- new(true, $1 && $1.split('_and_'))
13
- end
14
-
15
- def initialize(scope, attribute_names)
16
- @scope = scope
17
- @attribute_names = attribute_names
18
- end
19
-
20
- attr_reader :scope, :attribute_names
21
- alias :scope? :scope
22
- end
23
- end