activerecord_csi 2.3.5.p6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (333) hide show
  1. data/CHANGELOG +5858 -0
  2. data/README +351 -0
  3. data/RUNNING_UNIT_TESTS +36 -0
  4. data/Rakefile +270 -0
  5. data/examples/associations.png +0 -0
  6. data/examples/performance.rb +162 -0
  7. data/install.rb +30 -0
  8. data/lib/active_record/aggregations.rb +261 -0
  9. data/lib/active_record/association_preload.rb +389 -0
  10. data/lib/active_record/associations/association_collection.rb +475 -0
  11. data/lib/active_record/associations/association_proxy.rb +278 -0
  12. data/lib/active_record/associations/belongs_to_association.rb +76 -0
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +53 -0
  14. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +143 -0
  15. data/lib/active_record/associations/has_many_association.rb +122 -0
  16. data/lib/active_record/associations/has_many_through_association.rb +266 -0
  17. data/lib/active_record/associations/has_one_association.rb +133 -0
  18. data/lib/active_record/associations/has_one_through_association.rb +37 -0
  19. data/lib/active_record/associations.rb +2241 -0
  20. data/lib/active_record/attribute_methods.rb +388 -0
  21. data/lib/active_record/autosave_association.rb +364 -0
  22. data/lib/active_record/base.rb +3171 -0
  23. data/lib/active_record/batches.rb +81 -0
  24. data/lib/active_record/calculations.rb +311 -0
  25. data/lib/active_record/callbacks.rb +360 -0
  26. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +371 -0
  27. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +139 -0
  28. data/lib/active_record/connection_adapters/abstract/database_statements.rb +289 -0
  29. data/lib/active_record/connection_adapters/abstract/query_cache.rb +94 -0
  30. data/lib/active_record/connection_adapters/abstract/quoting.rb +69 -0
  31. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +722 -0
  32. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +434 -0
  33. data/lib/active_record/connection_adapters/abstract_adapter.rb +241 -0
  34. data/lib/active_record/connection_adapters/mysql_adapter.rb +630 -0
  35. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1113 -0
  36. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -0
  37. data/lib/active_record/connection_adapters/sqlite_adapter.rb +453 -0
  38. data/lib/active_record/dirty.rb +183 -0
  39. data/lib/active_record/dynamic_finder_match.rb +41 -0
  40. data/lib/active_record/dynamic_scope_match.rb +25 -0
  41. data/lib/active_record/fixtures.rb +996 -0
  42. data/lib/active_record/i18n_interpolation_deprecation.rb +26 -0
  43. data/lib/active_record/locale/en.yml +58 -0
  44. data/lib/active_record/locking/optimistic.rb +148 -0
  45. data/lib/active_record/locking/pessimistic.rb +55 -0
  46. data/lib/active_record/migration.rb +566 -0
  47. data/lib/active_record/named_scope.rb +192 -0
  48. data/lib/active_record/nested_attributes.rb +392 -0
  49. data/lib/active_record/observer.rb +197 -0
  50. data/lib/active_record/query_cache.rb +33 -0
  51. data/lib/active_record/reflection.rb +320 -0
  52. data/lib/active_record/schema.rb +51 -0
  53. data/lib/active_record/schema_dumper.rb +182 -0
  54. data/lib/active_record/serialization.rb +101 -0
  55. data/lib/active_record/serializers/json_serializer.rb +91 -0
  56. data/lib/active_record/serializers/xml_serializer.rb +357 -0
  57. data/lib/active_record/session_store.rb +326 -0
  58. data/lib/active_record/test_case.rb +66 -0
  59. data/lib/active_record/timestamp.rb +71 -0
  60. data/lib/active_record/transactions.rb +235 -0
  61. data/lib/active_record/validations.rb +1135 -0
  62. data/lib/active_record/version.rb +9 -0
  63. data/lib/active_record.rb +84 -0
  64. data/lib/activerecord.rb +2 -0
  65. data/test/assets/example.log +1 -0
  66. data/test/assets/flowers.jpg +0 -0
  67. data/test/cases/aaa_create_tables_test.rb +24 -0
  68. data/test/cases/active_schema_test_mysql.rb +100 -0
  69. data/test/cases/active_schema_test_postgresql.rb +24 -0
  70. data/test/cases/adapter_test.rb +145 -0
  71. data/test/cases/aggregations_test.rb +167 -0
  72. data/test/cases/ar_schema_test.rb +32 -0
  73. data/test/cases/associations/belongs_to_associations_test.rb +425 -0
  74. data/test/cases/associations/callbacks_test.rb +161 -0
  75. data/test/cases/associations/cascaded_eager_loading_test.rb +131 -0
  76. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +36 -0
  77. data/test/cases/associations/eager_load_nested_include_test.rb +130 -0
  78. data/test/cases/associations/eager_singularization_test.rb +145 -0
  79. data/test/cases/associations/eager_test.rb +834 -0
  80. data/test/cases/associations/extension_test.rb +62 -0
  81. data/test/cases/associations/habtm_join_table_test.rb +56 -0
  82. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +822 -0
  83. data/test/cases/associations/has_many_associations_test.rb +1134 -0
  84. data/test/cases/associations/has_many_through_associations_test.rb +346 -0
  85. data/test/cases/associations/has_one_associations_test.rb +330 -0
  86. data/test/cases/associations/has_one_through_associations_test.rb +209 -0
  87. data/test/cases/associations/inner_join_association_test.rb +93 -0
  88. data/test/cases/associations/join_model_test.rb +712 -0
  89. data/test/cases/associations_test.rb +262 -0
  90. data/test/cases/attribute_methods_test.rb +305 -0
  91. data/test/cases/autosave_association_test.rb +1142 -0
  92. data/test/cases/base_test.rb +2154 -0
  93. data/test/cases/batches_test.rb +61 -0
  94. data/test/cases/binary_test.rb +30 -0
  95. data/test/cases/calculations_test.rb +348 -0
  96. data/test/cases/callbacks_observers_test.rb +38 -0
  97. data/test/cases/callbacks_test.rb +438 -0
  98. data/test/cases/class_inheritable_attributes_test.rb +32 -0
  99. data/test/cases/column_alias_test.rb +17 -0
  100. data/test/cases/column_definition_test.rb +70 -0
  101. data/test/cases/connection_pool_test.rb +25 -0
  102. data/test/cases/connection_test_firebird.rb +8 -0
  103. data/test/cases/connection_test_mysql.rb +64 -0
  104. data/test/cases/copy_table_test_sqlite.rb +80 -0
  105. data/test/cases/database_statements_test.rb +12 -0
  106. data/test/cases/datatype_test_postgresql.rb +204 -0
  107. data/test/cases/date_time_test.rb +37 -0
  108. data/test/cases/default_test_firebird.rb +16 -0
  109. data/test/cases/defaults_test.rb +111 -0
  110. data/test/cases/deprecated_finder_test.rb +30 -0
  111. data/test/cases/dirty_test.rb +316 -0
  112. data/test/cases/finder_respond_to_test.rb +76 -0
  113. data/test/cases/finder_test.rb +1066 -0
  114. data/test/cases/fixtures_test.rb +656 -0
  115. data/test/cases/helper.rb +68 -0
  116. data/test/cases/i18n_test.rb +46 -0
  117. data/test/cases/inheritance_test.rb +262 -0
  118. data/test/cases/invalid_date_test.rb +24 -0
  119. data/test/cases/json_serialization_test.rb +205 -0
  120. data/test/cases/lifecycle_test.rb +193 -0
  121. data/test/cases/locking_test.rb +304 -0
  122. data/test/cases/method_scoping_test.rb +704 -0
  123. data/test/cases/migration_test.rb +1523 -0
  124. data/test/cases/migration_test_firebird.rb +124 -0
  125. data/test/cases/mixin_test.rb +96 -0
  126. data/test/cases/modules_test.rb +81 -0
  127. data/test/cases/multiple_db_test.rb +85 -0
  128. data/test/cases/named_scope_test.rb +361 -0
  129. data/test/cases/nested_attributes_test.rb +581 -0
  130. data/test/cases/pk_test.rb +119 -0
  131. data/test/cases/pooled_connections_test.rb +103 -0
  132. data/test/cases/query_cache_test.rb +123 -0
  133. data/test/cases/readonly_test.rb +107 -0
  134. data/test/cases/reflection_test.rb +194 -0
  135. data/test/cases/reload_models_test.rb +22 -0
  136. data/test/cases/repair_helper.rb +50 -0
  137. data/test/cases/reserved_word_test_mysql.rb +176 -0
  138. data/test/cases/sanitize_test.rb +25 -0
  139. data/test/cases/schema_authorization_test_postgresql.rb +75 -0
  140. data/test/cases/schema_dumper_test.rb +211 -0
  141. data/test/cases/schema_test_postgresql.rb +178 -0
  142. data/test/cases/serialization_test.rb +47 -0
  143. data/test/cases/synonym_test_oracle.rb +17 -0
  144. data/test/cases/timestamp_test.rb +75 -0
  145. data/test/cases/transactions_test.rb +522 -0
  146. data/test/cases/unconnected_test.rb +32 -0
  147. data/test/cases/validations_i18n_test.rb +955 -0
  148. data/test/cases/validations_test.rb +1640 -0
  149. data/test/cases/xml_serialization_test.rb +240 -0
  150. data/test/config.rb +5 -0
  151. data/test/connections/jdbc_jdbcderby/connection.rb +18 -0
  152. data/test/connections/jdbc_jdbch2/connection.rb +18 -0
  153. data/test/connections/jdbc_jdbchsqldb/connection.rb +18 -0
  154. data/test/connections/jdbc_jdbcmysql/connection.rb +26 -0
  155. data/test/connections/jdbc_jdbcpostgresql/connection.rb +26 -0
  156. data/test/connections/jdbc_jdbcsqlite3/connection.rb +25 -0
  157. data/test/connections/native_db2/connection.rb +25 -0
  158. data/test/connections/native_firebird/connection.rb +26 -0
  159. data/test/connections/native_frontbase/connection.rb +27 -0
  160. data/test/connections/native_mysql/connection.rb +25 -0
  161. data/test/connections/native_openbase/connection.rb +21 -0
  162. data/test/connections/native_oracle/connection.rb +27 -0
  163. data/test/connections/native_postgresql/connection.rb +25 -0
  164. data/test/connections/native_sqlite/connection.rb +25 -0
  165. data/test/connections/native_sqlite3/connection.rb +25 -0
  166. data/test/connections/native_sqlite3/in_memory_connection.rb +18 -0
  167. data/test/connections/native_sybase/connection.rb +23 -0
  168. data/test/fixtures/accounts.yml +29 -0
  169. data/test/fixtures/all/developers.yml +0 -0
  170. data/test/fixtures/all/people.csv +0 -0
  171. data/test/fixtures/all/tasks.yml +0 -0
  172. data/test/fixtures/author_addresses.yml +5 -0
  173. data/test/fixtures/author_favorites.yml +4 -0
  174. data/test/fixtures/authors.yml +9 -0
  175. data/test/fixtures/binaries.yml +132 -0
  176. data/test/fixtures/books.yml +7 -0
  177. data/test/fixtures/categories/special_categories.yml +9 -0
  178. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
  179. data/test/fixtures/categories.yml +14 -0
  180. data/test/fixtures/categories_ordered.yml +7 -0
  181. data/test/fixtures/categories_posts.yml +23 -0
  182. data/test/fixtures/categorizations.yml +17 -0
  183. data/test/fixtures/clubs.yml +6 -0
  184. data/test/fixtures/comments.yml +59 -0
  185. data/test/fixtures/companies.yml +56 -0
  186. data/test/fixtures/computers.yml +4 -0
  187. data/test/fixtures/courses.yml +7 -0
  188. data/test/fixtures/customers.yml +26 -0
  189. data/test/fixtures/developers.yml +21 -0
  190. data/test/fixtures/developers_projects.yml +17 -0
  191. data/test/fixtures/edges.yml +6 -0
  192. data/test/fixtures/entrants.yml +14 -0
  193. data/test/fixtures/fixture_database.sqlite3 +0 -0
  194. data/test/fixtures/fixture_database_2.sqlite3 +0 -0
  195. data/test/fixtures/fk_test_has_fk.yml +3 -0
  196. data/test/fixtures/fk_test_has_pk.yml +2 -0
  197. data/test/fixtures/funny_jokes.yml +10 -0
  198. data/test/fixtures/items.yml +4 -0
  199. data/test/fixtures/jobs.yml +7 -0
  200. data/test/fixtures/legacy_things.yml +3 -0
  201. data/test/fixtures/mateys.yml +4 -0
  202. data/test/fixtures/member_types.yml +6 -0
  203. data/test/fixtures/members.yml +6 -0
  204. data/test/fixtures/memberships.yml +20 -0
  205. data/test/fixtures/minimalistics.yml +2 -0
  206. data/test/fixtures/mixed_case_monkeys.yml +6 -0
  207. data/test/fixtures/mixins.yml +29 -0
  208. data/test/fixtures/movies.yml +7 -0
  209. data/test/fixtures/naked/csv/accounts.csv +1 -0
  210. data/test/fixtures/naked/yml/accounts.yml +1 -0
  211. data/test/fixtures/naked/yml/companies.yml +1 -0
  212. data/test/fixtures/naked/yml/courses.yml +1 -0
  213. data/test/fixtures/organizations.yml +5 -0
  214. data/test/fixtures/owners.yml +7 -0
  215. data/test/fixtures/parrots.yml +27 -0
  216. data/test/fixtures/parrots_pirates.yml +7 -0
  217. data/test/fixtures/people.yml +15 -0
  218. data/test/fixtures/pets.yml +14 -0
  219. data/test/fixtures/pirates.yml +9 -0
  220. data/test/fixtures/posts.yml +52 -0
  221. data/test/fixtures/price_estimates.yml +7 -0
  222. data/test/fixtures/projects.yml +7 -0
  223. data/test/fixtures/readers.yml +9 -0
  224. data/test/fixtures/references.yml +17 -0
  225. data/test/fixtures/reserved_words/distinct.yml +5 -0
  226. data/test/fixtures/reserved_words/distincts_selects.yml +11 -0
  227. data/test/fixtures/reserved_words/group.yml +14 -0
  228. data/test/fixtures/reserved_words/select.yml +8 -0
  229. data/test/fixtures/reserved_words/values.yml +7 -0
  230. data/test/fixtures/ships.yml +5 -0
  231. data/test/fixtures/sponsors.yml +9 -0
  232. data/test/fixtures/subscribers.yml +7 -0
  233. data/test/fixtures/subscriptions.yml +12 -0
  234. data/test/fixtures/taggings.yml +28 -0
  235. data/test/fixtures/tags.yml +7 -0
  236. data/test/fixtures/tasks.yml +7 -0
  237. data/test/fixtures/topics.yml +42 -0
  238. data/test/fixtures/toys.yml +4 -0
  239. data/test/fixtures/treasures.yml +10 -0
  240. data/test/fixtures/vertices.yml +4 -0
  241. data/test/fixtures/warehouse-things.yml +3 -0
  242. data/test/migrations/broken/100_migration_that_raises_exception.rb +10 -0
  243. data/test/migrations/decimal/1_give_me_big_numbers.rb +15 -0
  244. data/test/migrations/duplicate/1_people_have_last_names.rb +9 -0
  245. data/test/migrations/duplicate/2_we_need_reminders.rb +12 -0
  246. data/test/migrations/duplicate/3_foo.rb +7 -0
  247. data/test/migrations/duplicate/3_innocent_jointable.rb +12 -0
  248. data/test/migrations/duplicate_names/20080507052938_chunky.rb +7 -0
  249. data/test/migrations/duplicate_names/20080507053028_chunky.rb +7 -0
  250. data/test/migrations/interleaved/pass_1/3_innocent_jointable.rb +12 -0
  251. data/test/migrations/interleaved/pass_2/1_people_have_last_names.rb +9 -0
  252. data/test/migrations/interleaved/pass_2/3_innocent_jointable.rb +12 -0
  253. data/test/migrations/interleaved/pass_3/1_people_have_last_names.rb +9 -0
  254. data/test/migrations/interleaved/pass_3/2_i_raise_on_down.rb +8 -0
  255. data/test/migrations/interleaved/pass_3/3_innocent_jointable.rb +12 -0
  256. data/test/migrations/missing/1000_people_have_middle_names.rb +9 -0
  257. data/test/migrations/missing/1_people_have_last_names.rb +9 -0
  258. data/test/migrations/missing/3_we_need_reminders.rb +12 -0
  259. data/test/migrations/missing/4_innocent_jointable.rb +12 -0
  260. data/test/migrations/valid/1_people_have_last_names.rb +9 -0
  261. data/test/migrations/valid/2_we_need_reminders.rb +12 -0
  262. data/test/migrations/valid/3_innocent_jointable.rb +12 -0
  263. data/test/models/author.rb +146 -0
  264. data/test/models/auto_id.rb +4 -0
  265. data/test/models/binary.rb +2 -0
  266. data/test/models/bird.rb +3 -0
  267. data/test/models/book.rb +4 -0
  268. data/test/models/categorization.rb +5 -0
  269. data/test/models/category.rb +34 -0
  270. data/test/models/citation.rb +6 -0
  271. data/test/models/club.rb +13 -0
  272. data/test/models/column_name.rb +3 -0
  273. data/test/models/comment.rb +29 -0
  274. data/test/models/company.rb +171 -0
  275. data/test/models/company_in_module.rb +61 -0
  276. data/test/models/computer.rb +3 -0
  277. data/test/models/contact.rb +16 -0
  278. data/test/models/contract.rb +5 -0
  279. data/test/models/course.rb +3 -0
  280. data/test/models/customer.rb +73 -0
  281. data/test/models/default.rb +2 -0
  282. data/test/models/developer.rb +101 -0
  283. data/test/models/edge.rb +5 -0
  284. data/test/models/entrant.rb +3 -0
  285. data/test/models/essay.rb +3 -0
  286. data/test/models/event.rb +3 -0
  287. data/test/models/guid.rb +2 -0
  288. data/test/models/item.rb +7 -0
  289. data/test/models/job.rb +5 -0
  290. data/test/models/joke.rb +3 -0
  291. data/test/models/keyboard.rb +3 -0
  292. data/test/models/legacy_thing.rb +3 -0
  293. data/test/models/matey.rb +4 -0
  294. data/test/models/member.rb +12 -0
  295. data/test/models/member_detail.rb +5 -0
  296. data/test/models/member_type.rb +3 -0
  297. data/test/models/membership.rb +9 -0
  298. data/test/models/minimalistic.rb +2 -0
  299. data/test/models/mixed_case_monkey.rb +3 -0
  300. data/test/models/movie.rb +5 -0
  301. data/test/models/order.rb +4 -0
  302. data/test/models/organization.rb +6 -0
  303. data/test/models/owner.rb +5 -0
  304. data/test/models/parrot.rb +16 -0
  305. data/test/models/person.rb +16 -0
  306. data/test/models/pet.rb +5 -0
  307. data/test/models/pirate.rb +70 -0
  308. data/test/models/post.rb +100 -0
  309. data/test/models/price_estimate.rb +3 -0
  310. data/test/models/project.rb +30 -0
  311. data/test/models/reader.rb +4 -0
  312. data/test/models/reference.rb +4 -0
  313. data/test/models/reply.rb +46 -0
  314. data/test/models/ship.rb +10 -0
  315. data/test/models/ship_part.rb +5 -0
  316. data/test/models/sponsor.rb +4 -0
  317. data/test/models/subject.rb +4 -0
  318. data/test/models/subscriber.rb +8 -0
  319. data/test/models/subscription.rb +4 -0
  320. data/test/models/tag.rb +7 -0
  321. data/test/models/tagging.rb +10 -0
  322. data/test/models/task.rb +3 -0
  323. data/test/models/topic.rb +80 -0
  324. data/test/models/toy.rb +6 -0
  325. data/test/models/treasure.rb +8 -0
  326. data/test/models/vertex.rb +9 -0
  327. data/test/models/warehouse_thing.rb +5 -0
  328. data/test/schema/mysql_specific_schema.rb +24 -0
  329. data/test/schema/postgresql_specific_schema.rb +114 -0
  330. data/test/schema/schema.rb +493 -0
  331. data/test/schema/schema2.rb +6 -0
  332. data/test/schema/sqlite_specific_schema.rb +25 -0
  333. metadata +420 -0
@@ -0,0 +1,182 @@
1
+ require 'stringio'
2
+ require 'bigdecimal'
3
+
4
+ module ActiveRecord
5
+ # This class is used to dump the database schema for some connection to some
6
+ # output format (i.e., ActiveRecord::Schema).
7
+ class SchemaDumper #:nodoc:
8
+ private_class_method :new
9
+
10
+ ##
11
+ # :singleton-method:
12
+ # A list of tables which should not be dumped to the schema.
13
+ # Acceptable values are strings as well as regexp.
14
+ # This setting is only used if ActiveRecord::Base.schema_format == :ruby
15
+ cattr_accessor :ignore_tables
16
+ @@ignore_tables = []
17
+
18
+ def self.dump(connection=ActiveRecord::Base.connection, stream=STDOUT)
19
+ new(connection).dump(stream)
20
+ stream
21
+ end
22
+
23
+ def dump(stream)
24
+ header(stream)
25
+ tables(stream)
26
+ trailer(stream)
27
+ stream
28
+ end
29
+
30
+ private
31
+
32
+ def initialize(connection)
33
+ @connection = connection
34
+ @types = @connection.native_database_types
35
+ @version = Migrator::current_version rescue nil
36
+ end
37
+
38
+ def header(stream)
39
+ define_params = @version ? ":version => #{@version}" : ""
40
+
41
+ stream.puts <<HEADER
42
+ # This file is auto-generated from the current state of the database. Instead of editing this file,
43
+ # please use the migrations feature of Active Record to incrementally modify your database, and
44
+ # then regenerate this schema definition.
45
+ #
46
+ # Note that this schema.rb definition is the authoritative source for your database schema. If you need
47
+ # to create the application database on another system, you should be using db:schema:load, not running
48
+ # all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
49
+ # you'll amass, the slower it'll run and the greater likelihood for issues).
50
+ #
51
+ # It's strongly recommended to check this file into your version control system.
52
+
53
+ ActiveRecord::Schema.define(#{define_params}) do
54
+
55
+ HEADER
56
+ end
57
+
58
+ def trailer(stream)
59
+ stream.puts "end"
60
+ end
61
+
62
+ def tables(stream)
63
+ @connection.tables.sort.each do |tbl|
64
+ next if ['schema_migrations', ignore_tables].flatten.any? do |ignored|
65
+ case ignored
66
+ when String; tbl == ignored
67
+ when Regexp; tbl =~ ignored
68
+ else
69
+ raise StandardError, 'ActiveRecord::SchemaDumper.ignore_tables accepts an array of String and / or Regexp values.'
70
+ end
71
+ end
72
+ table(tbl, stream)
73
+ end
74
+ end
75
+
76
+ def table(table, stream)
77
+ columns = @connection.columns(table)
78
+ begin
79
+ tbl = StringIO.new
80
+
81
+ # first dump primary key column
82
+ if @connection.respond_to?(:pk_and_sequence_for)
83
+ pk, pk_seq = @connection.pk_and_sequence_for(table)
84
+ elsif @connection.respond_to?(:primary_key)
85
+ pk = @connection.primary_key(table)
86
+ end
87
+
88
+ tbl.print " create_table #{table.inspect}"
89
+ if columns.detect { |c| c.name == pk }
90
+ if pk != 'id'
91
+ tbl.print %Q(, :primary_key => "#{pk}")
92
+ end
93
+ else
94
+ tbl.print ", :id => false"
95
+ end
96
+ tbl.print ", :force => true"
97
+ tbl.puts " do |t|"
98
+
99
+ # then dump all non-primary key columns
100
+ column_specs = columns.map do |column|
101
+ raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" if @types[column.type].nil?
102
+ next if column.name == pk
103
+ spec = {}
104
+ spec[:name] = column.name.inspect
105
+ spec[:type] = column.type.to_s
106
+ spec[:limit] = column.limit.inspect if column.limit != @types[column.type][:limit] && column.type != :decimal
107
+ spec[:precision] = column.precision.inspect if !column.precision.nil?
108
+ spec[:scale] = column.scale.inspect if !column.scale.nil?
109
+ spec[:null] = 'false' if !column.null
110
+ spec[:default] = default_string(column.default) if column.has_default?
111
+ (spec.keys - [:name, :type]).each{ |k| spec[k].insert(0, "#{k.inspect} => ")}
112
+ spec
113
+ end.compact
114
+
115
+ # find all migration keys used in this table
116
+ keys = [:name, :limit, :precision, :scale, :default, :null] & column_specs.map(&:keys).flatten
117
+
118
+ # figure out the lengths for each column based on above keys
119
+ lengths = keys.map{ |key| column_specs.map{ |spec| spec[key] ? spec[key].length + 2 : 0 }.max }
120
+
121
+ # the string we're going to sprintf our values against, with standardized column widths
122
+ format_string = lengths.map{ |len| "%-#{len}s" }
123
+
124
+ # find the max length for the 'type' column, which is special
125
+ type_length = column_specs.map{ |column| column[:type].length }.max
126
+
127
+ # add column type definition to our format string
128
+ format_string.unshift " t.%-#{type_length}s "
129
+
130
+ format_string *= ''
131
+
132
+ column_specs.each do |colspec|
133
+ values = keys.zip(lengths).map{ |key, len| colspec.key?(key) ? colspec[key] + ", " : " " * len }
134
+ values.unshift colspec[:type]
135
+ tbl.print((format_string % values).gsub(/,\s*$/, ''))
136
+ tbl.puts
137
+ end
138
+
139
+ tbl.puts " end"
140
+ tbl.puts
141
+
142
+ indexes(table, tbl)
143
+
144
+ tbl.rewind
145
+ stream.print tbl.read
146
+ rescue => e
147
+ stream.puts "# Could not dump table #{table.inspect} because of following #{e.class}"
148
+ stream.puts "# #{e.message}"
149
+ stream.puts
150
+ end
151
+
152
+ stream
153
+ end
154
+
155
+ def default_string(value)
156
+ case value
157
+ when BigDecimal
158
+ value.to_s
159
+ when Date, DateTime, Time
160
+ "'" + value.to_s(:db) + "'"
161
+ else
162
+ value.inspect
163
+ end
164
+ end
165
+
166
+ def indexes(table, stream)
167
+ if (indexes = @connection.indexes(table)).any?
168
+ add_index_statements = indexes.map do |index|
169
+ statment_parts = [ ('add_index ' + index.table.inspect) ]
170
+ statment_parts << index.columns.inspect
171
+ statment_parts << (':name => ' + index.name.inspect)
172
+ statment_parts << ':unique => true' if index.unique
173
+
174
+ ' ' + statment_parts.join(', ')
175
+ end
176
+
177
+ stream.puts add_index_statements.sort.join("\n")
178
+ stream.puts
179
+ end
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,101 @@
1
+ require 'active_support/json'
2
+
3
+ module ActiveRecord #:nodoc:
4
+ module Serialization
5
+ class Serializer #:nodoc:
6
+ attr_reader :options
7
+
8
+ def initialize(record, options = nil)
9
+ @record = record
10
+ @options = options ? options.dup : {}
11
+ end
12
+
13
+ # To replicate the behavior in ActiveRecord#attributes,
14
+ # <tt>:except</tt> takes precedence over <tt>:only</tt>. If <tt>:only</tt> is not set
15
+ # for a N level model but is set for the N+1 level models,
16
+ # then because <tt>:except</tt> is set to a default value, the second
17
+ # level model can have both <tt>:except</tt> and <tt>:only</tt> set. So if
18
+ # <tt>:only</tt> is set, always delete <tt>:except</tt>.
19
+ def serializable_attribute_names
20
+ attribute_names = @record.attribute_names
21
+
22
+ if options[:only]
23
+ options.delete(:except)
24
+ attribute_names = attribute_names & Array(options[:only]).collect { |n| n.to_s }
25
+ else
26
+ options[:except] = Array(options[:except]) | Array(@record.class.inheritance_column)
27
+ attribute_names = attribute_names - options[:except].collect { |n| n.to_s }
28
+ end
29
+
30
+ attribute_names
31
+ end
32
+
33
+ def serializable_method_names
34
+ Array(options[:methods]).inject([]) do |method_attributes, name|
35
+ method_attributes << name if @record.respond_to?(name.to_s)
36
+ method_attributes
37
+ end
38
+ end
39
+
40
+ def serializable_names
41
+ serializable_attribute_names + serializable_method_names
42
+ end
43
+
44
+ # Add associations specified via the <tt>:includes</tt> option.
45
+ # Expects a block that takes as arguments:
46
+ # +association+ - name of the association
47
+ # +records+ - the association record(s) to be serialized
48
+ # +opts+ - options for the association records
49
+ def add_includes(&block)
50
+ if include_associations = options.delete(:include)
51
+ base_only_or_except = { :except => options[:except],
52
+ :only => options[:only] }
53
+
54
+ include_has_options = include_associations.is_a?(Hash)
55
+ associations = include_has_options ? include_associations.keys : Array(include_associations)
56
+
57
+ for association in associations
58
+ records = case @record.class.reflect_on_association(association).macro
59
+ when :has_many, :has_and_belongs_to_many
60
+ @record.send(association).to_a
61
+ when :has_one, :belongs_to
62
+ @record.send(association)
63
+ end
64
+
65
+ unless records.nil?
66
+ association_options = include_has_options ? include_associations[association] : base_only_or_except
67
+ opts = options.merge(association_options)
68
+ yield(association, records, opts)
69
+ end
70
+ end
71
+
72
+ options[:include] = include_associations
73
+ end
74
+ end
75
+
76
+ def serializable_record
77
+ returning(serializable_record = {}) do
78
+ serializable_names.each { |name| serializable_record[name] = @record.send(name) }
79
+ add_includes do |association, records, opts|
80
+ if records.is_a?(Enumerable)
81
+ serializable_record[association] = records.collect { |r| self.class.new(r, opts).serializable_record }
82
+ else
83
+ serializable_record[association] = self.class.new(records, opts).serializable_record
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ def serialize
90
+ # overwrite to implement
91
+ end
92
+
93
+ def to_s(&block)
94
+ serialize(&block)
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ require 'active_record/serializers/xml_serializer'
101
+ require 'active_record/serializers/json_serializer'
@@ -0,0 +1,91 @@
1
+ require 'active_support/json'
2
+ require 'active_support/core_ext/module/model_naming'
3
+
4
+ module ActiveRecord #:nodoc:
5
+ module Serialization
6
+ def self.included(base)
7
+ base.cattr_accessor :include_root_in_json, :instance_writer => false
8
+ end
9
+
10
+ # Returns a JSON string representing the model. Some configuration is
11
+ # available through +options+.
12
+ #
13
+ # The option <tt>ActiveRecord::Base.include_root_in_json</tt> controls the
14
+ # top-level behavior of to_json. In a new Rails application, it is set to
15
+ # <tt>true</tt> in initializers/new_rails_defaults.rb. When it is <tt>true</tt>,
16
+ # to_json will emit a single root node named after the object's type. For example:
17
+ #
18
+ # konata = User.find(1)
19
+ # ActiveRecord::Base.include_root_in_json = true
20
+ # konata.to_json
21
+ # # => { "user": {"id": 1, "name": "Konata Izumi", "age": 16,
22
+ # "created_at": "2006/08/01", "awesome": true} }
23
+ #
24
+ # ActiveRecord::Base.include_root_in_json = false
25
+ # konata.to_json
26
+ # # => {"id": 1, "name": "Konata Izumi", "age": 16,
27
+ # "created_at": "2006/08/01", "awesome": true}
28
+ #
29
+ # The remainder of the examples in this section assume include_root_in_json is set to
30
+ # <tt>false</tt>.
31
+ #
32
+ # Without any +options+, the returned JSON string will include all
33
+ # the model's attributes. For example:
34
+ #
35
+ # konata = User.find(1)
36
+ # konata.to_json
37
+ # # => {"id": 1, "name": "Konata Izumi", "age": 16,
38
+ # "created_at": "2006/08/01", "awesome": true}
39
+ #
40
+ # The <tt>:only</tt> and <tt>:except</tt> options can be used to limit the attributes
41
+ # included, and work similar to the +attributes+ method. For example:
42
+ #
43
+ # konata.to_json(:only => [ :id, :name ])
44
+ # # => {"id": 1, "name": "Konata Izumi"}
45
+ #
46
+ # konata.to_json(:except => [ :id, :created_at, :age ])
47
+ # # => {"name": "Konata Izumi", "awesome": true}
48
+ #
49
+ # To include any methods on the model, use <tt>:methods</tt>.
50
+ #
51
+ # konata.to_json(:methods => :permalink)
52
+ # # => {"id": 1, "name": "Konata Izumi", "age": 16,
53
+ # "created_at": "2006/08/01", "awesome": true,
54
+ # "permalink": "1-konata-izumi"}
55
+ #
56
+ # To include associations, use <tt>:include</tt>.
57
+ #
58
+ # konata.to_json(:include => :posts)
59
+ # # => {"id": 1, "name": "Konata Izumi", "age": 16,
60
+ # "created_at": "2006/08/01", "awesome": true,
61
+ # "posts": [{"id": 1, "author_id": 1, "title": "Welcome to the weblog"},
62
+ # {"id": 2, author_id: 1, "title": "So I was thinking"}]}
63
+ #
64
+ # 2nd level and higher order associations work as well:
65
+ #
66
+ # konata.to_json(:include => { :posts => {
67
+ # :include => { :comments => {
68
+ # :only => :body } },
69
+ # :only => :title } })
70
+ # # => {"id": 1, "name": "Konata Izumi", "age": 16,
71
+ # "created_at": "2006/08/01", "awesome": true,
72
+ # "posts": [{"comments": [{"body": "1st post!"}, {"body": "Second!"}],
73
+ # "title": "Welcome to the weblog"},
74
+ # {"comments": [{"body": "Don't think too hard"}],
75
+ # "title": "So I was thinking"}]}
76
+ def to_json(options = {})
77
+ super
78
+ end
79
+
80
+ def as_json(options = nil) #:nodoc:
81
+ hash = Serializer.new(self, options).serializable_record
82
+ hash = { self.class.model_name.element => hash } if include_root_in_json
83
+ hash
84
+ end
85
+
86
+ def from_json(json)
87
+ self.attributes = ActiveSupport::JSON.decode(json)
88
+ self
89
+ end
90
+ end
91
+ end