activerecord-jdbc-adapter 1.2.5 → 1.2.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (155) hide show
  1. data/.gitignore +1 -0
  2. data/.travis.yml +5 -1
  3. data/Appraisals +5 -5
  4. data/Gemfile +9 -1
  5. data/Gemfile.lock +44 -10
  6. data/History.txt +126 -2
  7. data/README.md +246 -0
  8. data/Rakefile +34 -25
  9. data/activerecord-jdbc-adapter.gemspec +1 -1
  10. data/gemfiles/rails23.gemfile +5 -3
  11. data/gemfiles/rails23.gemfile.lock +26 -18
  12. data/gemfiles/rails30.gemfile +4 -2
  13. data/gemfiles/rails30.gemfile.lock +16 -8
  14. data/gemfiles/rails31.gemfile +4 -2
  15. data/gemfiles/rails31.gemfile.lock +16 -9
  16. data/gemfiles/rails32.gemfile +4 -2
  17. data/gemfiles/rails32.gemfile.lock +15 -8
  18. data/lib/active_record/connection_adapters/db2_adapter.rb +1 -0
  19. data/lib/arel/visitors/sql_server.rb +3 -0
  20. data/lib/arjdbc.rb +3 -5
  21. data/lib/arjdbc/db2.rb +1 -0
  22. data/lib/arjdbc/db2/adapter.rb +302 -196
  23. data/lib/arjdbc/db2/connection_methods.rb +18 -0
  24. data/lib/arjdbc/derby/active_record_patch.rb +12 -0
  25. data/lib/arjdbc/derby/adapter.rb +180 -158
  26. data/lib/arjdbc/derby/connection_methods.rb +5 -1
  27. data/lib/arjdbc/firebird/adapter.rb +27 -19
  28. data/lib/arjdbc/h2/adapter.rb +162 -7
  29. data/lib/arjdbc/h2/connection_methods.rb +5 -1
  30. data/lib/arjdbc/hsqldb.rb +1 -1
  31. data/lib/arjdbc/hsqldb/adapter.rb +96 -61
  32. data/lib/arjdbc/hsqldb/connection_methods.rb +5 -1
  33. data/lib/arjdbc/hsqldb/explain_support.rb +35 -0
  34. data/lib/arjdbc/informix/adapter.rb +56 -55
  35. data/lib/arjdbc/jdbc/adapter.rb +173 -86
  36. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  37. data/lib/arjdbc/jdbc/column.rb +28 -23
  38. data/lib/arjdbc/jdbc/connection.rb +10 -6
  39. data/lib/arjdbc/jdbc/driver.rb +13 -5
  40. data/lib/arjdbc/jdbc/serialized_attributes_helper.rb +21 -0
  41. data/lib/arjdbc/mssql.rb +1 -1
  42. data/lib/arjdbc/mssql/adapter.rb +51 -53
  43. data/lib/arjdbc/mssql/connection_methods.rb +8 -1
  44. data/lib/arjdbc/mysql.rb +1 -1
  45. data/lib/arjdbc/mysql/adapter.rb +186 -150
  46. data/lib/arjdbc/mysql/connection_methods.rb +9 -9
  47. data/lib/arjdbc/mysql/explain_support.rb +85 -0
  48. data/lib/arjdbc/oracle.rb +1 -1
  49. data/lib/arjdbc/oracle/adapter.rb +232 -125
  50. data/lib/arjdbc/oracle/connection_methods.rb +2 -2
  51. data/lib/arjdbc/postgresql.rb +1 -1
  52. data/lib/arjdbc/postgresql/adapter.rb +134 -86
  53. data/lib/arjdbc/postgresql/connection_methods.rb +6 -4
  54. data/lib/arjdbc/postgresql/explain_support.rb +55 -0
  55. data/lib/arjdbc/sqlite3.rb +1 -1
  56. data/lib/arjdbc/sqlite3/adapter.rb +176 -108
  57. data/lib/arjdbc/sqlite3/connection_methods.rb +5 -5
  58. data/lib/arjdbc/sqlite3/explain_support.rb +32 -0
  59. data/lib/arjdbc/sybase/adapter.rb +7 -6
  60. data/lib/arjdbc/version.rb +1 -1
  61. data/pom.xml +1 -1
  62. data/rakelib/02-test.rake +9 -11
  63. data/rakelib/rails.rake +18 -10
  64. data/src/java/arjdbc/db2/DB2Module.java +70 -0
  65. data/src/java/arjdbc/derby/DerbyModule.java +24 -5
  66. data/src/java/arjdbc/hsqldb/HSQLDBModule.java +66 -0
  67. data/src/java/arjdbc/jdbc/AdapterJavaService.java +14 -7
  68. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +111 -89
  69. data/src/java/arjdbc/mysql/MySQLModule.java +79 -70
  70. data/src/java/arjdbc/oracle/OracleModule.java +74 -0
  71. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +5 -10
  72. data/src/java/arjdbc/sqlite3/SQLite3Module.java +77 -0
  73. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +127 -0
  74. data/src/java/arjdbc/sqlite3/Sqlite3RubyJdbcConnection.java +25 -111
  75. data/src/java/arjdbc/util/QuotingUtils.java +104 -0
  76. data/test/abstract_db_create.rb +6 -6
  77. data/test/activerecord/connection_adapters/type_conversion_test.rb +2 -2
  78. data/test/assets/flowers.jpg +0 -0
  79. data/test/binary.rb +67 -0
  80. data/test/db/db2.rb +30 -7
  81. data/test/db/jdbc.rb +4 -2
  82. data/test/db/oracle.rb +18 -27
  83. data/test/db2_binary_test.rb +6 -0
  84. data/test/db2_serialize_test.rb +6 -0
  85. data/test/db2_simple_test.rb +20 -25
  86. data/test/db2_test.rb +71 -0
  87. data/test/derby_binary_test.rb +6 -0
  88. data/test/derby_migration_test.rb +42 -35
  89. data/test/derby_reset_column_information_test.rb +1 -0
  90. data/test/derby_row_locking_test.rb +17 -0
  91. data/test/derby_schema_dump_test.rb +9 -0
  92. data/test/derby_serialize_test.rb +6 -0
  93. data/test/derby_simple_test.rb +59 -17
  94. data/test/generic_jdbc_connection_test.rb +112 -5
  95. data/test/h2_binary_test.rb +6 -0
  96. data/test/h2_change_column_test.rb +1 -1
  97. data/test/h2_schema_dump_test.rb +25 -0
  98. data/test/h2_serialize_test.rb +6 -0
  99. data/test/h2_simple_test.rb +23 -9
  100. data/test/has_many_through.rb +18 -4
  101. data/test/hsqldb_binary_test.rb +6 -0
  102. data/test/hsqldb_schema_dump_test.rb +15 -0
  103. data/test/hsqldb_serialize_test.rb +6 -0
  104. data/test/hsqldb_simple_test.rb +1 -0
  105. data/test/informix_simple_test.rb +1 -1
  106. data/test/jdbc/db2.rb +23 -0
  107. data/test/jdbc/oracle.rb +23 -0
  108. data/test/jdbc_common.rb +3 -110
  109. data/test/jndi_callbacks_test.rb +0 -2
  110. data/test/jndi_test.rb +2 -0
  111. data/test/models/binary.rb +18 -0
  112. data/test/models/custom_pk_name.rb +1 -0
  113. data/test/models/data_types.rb +11 -2
  114. data/test/models/entry.rb +1 -1
  115. data/test/models/string_id.rb +2 -2
  116. data/test/models/thing.rb +1 -1
  117. data/test/models/topic.rb +32 -0
  118. data/test/mssql_legacy_types_test.rb +1 -1
  119. data/test/mssql_limit_offset_test.rb +13 -3
  120. data/test/mssql_serialize_test.rb +6 -0
  121. data/test/mysql_binary_test.rb +6 -0
  122. data/test/mysql_schema_dump_test.rb +220 -0
  123. data/test/mysql_serialize_test.rb +6 -0
  124. data/test/mysql_simple_test.rb +22 -2
  125. data/test/mysql_test.rb +93 -0
  126. data/test/oracle_binary_test.rb +6 -0
  127. data/test/oracle_limit_test.rb +2 -1
  128. data/test/oracle_serialize_test.rb +6 -0
  129. data/test/oracle_simple_test.rb +61 -0
  130. data/test/oracle_specific_test.rb +77 -26
  131. data/test/postgres_binary_test.rb +6 -0
  132. data/test/postgres_native_type_mapping_test.rb +12 -11
  133. data/test/postgres_nonseq_pkey_test.rb +1 -0
  134. data/test/postgres_reserved_test.rb +1 -0
  135. data/test/postgres_reset_column_information_test.rb +1 -0
  136. data/test/postgres_row_locking_test.rb +21 -0
  137. data/test/postgres_schema_dump_test.rb +88 -0
  138. data/test/postgres_schema_search_path_test.rb +1 -0
  139. data/test/postgres_simple_test.rb +62 -89
  140. data/test/postgres_table_alias_length_test.rb +1 -0
  141. data/test/postgres_test.rb +31 -0
  142. data/test/postgres_type_conversion_test.rb +16 -16
  143. data/test/row_locking.rb +69 -64
  144. data/test/schema_dump.rb +168 -0
  145. data/test/serialize.rb +277 -0
  146. data/test/simple.rb +326 -122
  147. data/test/sqlite3_serialize_test.rb +6 -0
  148. data/test/sqlite3_simple_test.rb +51 -84
  149. data/test/sqlite3_type_conversion_test.rb +101 -0
  150. data/test/test_helper.rb +224 -0
  151. metadata +325 -366
  152. data/README.rdoc +0 -214
  153. data/test/db/logger.rb +0 -3
  154. data/test/derby_multibyte_test.rb +0 -11
  155. data/test/mysql_info_test.rb +0 -123
@@ -1,4 +1,5 @@
1
1
  require 'jdbc_common'
2
+ require 'db/postgres'
2
3
 
3
4
  class PostgresTableAliasLengthTest < Test::Unit::TestCase
4
5
  def test_table_alias_length
@@ -0,0 +1,31 @@
1
+ require 'test_helper'
2
+
3
+ class PostgresTest < Test::Unit::TestCase
4
+
5
+ test 'create_database (with options)' do
6
+ connection = connection_stub
7
+ connection.expects(:execute).with '' +
8
+ "CREATE DATABASE \"mega_development\" ENCODING='utf8' TABLESPACE = \"TS1\" OWNER = \"kimcom\""
9
+ connection.create_database 'mega_development',
10
+ :tablespace => :'TS1', 'owner' => 'kimcom', :invalid => 'ignored'
11
+ end
12
+
13
+ test 'create_database (no options)' do
14
+ connection = connection_stub
15
+ connection.expects(:execute).with "CREATE DATABASE \"mega_development\" ENCODING='utf8'"
16
+ connection.create_database 'mega_development'
17
+ end
18
+
19
+ private
20
+
21
+ def connection_stub
22
+ connection = mock('connection')
23
+ (class << connection; self; end).class_eval do
24
+ def self.alias_chained_method(*args); args; end
25
+ end
26
+ def connection.configure_connection; nil; end
27
+ connection.extend ArJdbc::PostgreSQL
28
+ connection
29
+ end
30
+
31
+ end
@@ -1,26 +1,27 @@
1
1
  require 'jdbc_common'
2
+ require 'db/postgres'
2
3
 
3
- class BooleanSchema < ActiveRecord::Migration
4
- def self.up
5
- create_table :booleans do |t|
6
- t.boolean :value, :default => false, :null => false
4
+ class PostgresTypeConversionTest < Test::Unit::TestCase
5
+
6
+ class BooleanSchema < ActiveRecord::Migration
7
+ def self.up
8
+ create_table :booleans do |t|
9
+ t.boolean :value, :default => false, :null => false
10
+ end
7
11
  end
8
- end
9
12
 
10
- def self.down
11
- drop_table :booleans
13
+ def self.down
14
+ drop_table :booleans
15
+ end
12
16
  end
13
- end
14
17
 
15
- class Boolean < ActiveRecord::Base
16
- end
17
-
18
- class PostgresTypeConversionTest < Test::Unit::TestCase
19
- def setup
18
+ class Boolean < ActiveRecord::Base; end
19
+
20
+ def self.startup
20
21
  BooleanSchema.up
21
22
  end
22
23
 
23
- def teardown
24
+ def self.shutdown
24
25
  BooleanSchema.down
25
26
  end
26
27
 
@@ -29,5 +30,4 @@ class PostgresTypeConversionTest < Test::Unit::TestCase
29
30
  ActiveRecord::Base.connection.raw_connection.set_native_database_types
30
31
  end
31
32
  end
32
- end
33
-
33
+ end
@@ -5,8 +5,10 @@ module RowLockingTestMethods
5
5
  # Simple SELECT ... FOR UPDATE test
6
6
  def test_select_all_for_update
7
7
  @row1_id = Entry.create!(:title => "row1").id
8
- assert Entry.lock(true).all.map{|row| row.id}.include?(@row1_id)
9
- end
8
+ all_locked = Entry.lock(true)
9
+ all_locked_ids = all_locked.all.map { |row| row.id }
10
+ assert all_locked_ids.include?(@row1_id)
11
+ end if Test::Unit::TestCase.ar_version('3.0')
10
12
 
11
13
  def test_row_locking
12
14
  row_locking_test_template
@@ -16,79 +18,82 @@ module RowLockingTestMethods
16
18
  row_locking_test_template(:limit => 1)
17
19
  end
18
20
 
19
- private
20
-
21
- def row_locking_test_template(options={})
22
- # Create two rows that we will work with
23
- @row1_id = Entry.create!(:title => "row1").id
24
- @row2_id = Entry.create!(:title => "row2").id
21
+ protected
22
+
23
+ def row_locking_test_template(options={})
24
+ # Create two rows that we will work with
25
+ @row1_id = Entry.create!(:title => "row1").id
26
+ @row2_id = Entry.create!(:title => "row2").id
25
27
 
26
- @result_queue = Queue.new
27
- signal_queue = Queue.new
28
- t1 = Thread.new { thread_helper { thread1_main(signal_queue, options) } }
29
- t2 = Thread.new { thread_helper { thread2_main(signal_queue, options) } }
30
- t1.join
31
- t2.join
28
+ @result_queue = Queue.new
29
+ signal_queue = Queue.new
30
+ t1 = Thread.new { thread_helper { thread1_main(signal_queue, options) } }
31
+ t2 = Thread.new { thread_helper { thread2_main(signal_queue, options) } }
32
+ t1.join
33
+ t2.join
32
34
 
33
- result = []
34
- result << @result_queue.shift until @result_queue.empty? # Convert the queue into an array
35
+ result = []
36
+ result << @result_queue.shift until @result_queue.empty? # Convert the queue into an array
35
37
 
36
- expected = [
37
- :t1_locking_row2,
38
- :t1_locked_row2,
38
+ expected = [
39
+ :t1_locking_row2,
40
+ :t1_locked_row2,
39
41
 
40
- :t2_locking_row1,
41
- :t2_locked_row1,
42
+ :t2_locking_row1,
43
+ :t2_locked_row1,
42
44
 
43
- :t2_locking_row2, # thread 2 tries to lock row2 ...
44
- :t1_committed,
45
- :t2_locked_row2, # ... but it doesn't succeed until after thread 1 commits its transaction
45
+ :t2_locking_row2, # thread 2 tries to lock row2 ...
46
+ :t1_committed,
47
+ :t2_locked_row2, # ... but it doesn't succeed until after thread 1 commits its transaction
46
48
 
47
- :t2_committed,
48
- ]
49
+ :t2_committed,
50
+ ]
49
51
 
50
- assert_equal expected, result, "thread2 should lock row1 immediately but wait for thread1 to commit before getting the lock on row2"
51
- end
52
+ assert_equal expected, result, "thread2 should lock row1 immediately but wait for thread1 to commit before getting the lock on row2"
53
+ end
54
+
55
+ private
52
56
 
53
- def thread1_main(signal_queue, options={})
54
- Entry.transaction do
55
- @result_queue << :t1_locking_row2
56
- Entry.find(@row2_id, {:lock=>true}.merge(options)) # acquire a row lock on r2
57
- @result_queue << :t1_locked_row2
58
- signal_queue << :go # signal thread2 to start
59
- sleep 2.0 # Wait for a few seconds, to allow the other thread to race with this thread.
60
- @result_queue << :t1_committed
61
- end
57
+ def thread1_main(signal_queue, options={})
58
+ Entry.transaction do
59
+ @result_queue << :t1_locking_row2
60
+ Entry.find(@row2_id, {:lock=>true}.merge(options)) # acquire a row lock on r2
61
+ @result_queue << :t1_locked_row2
62
+ signal_queue << :go # signal thread2 to start
63
+ sleep 1.5 # Wait for a few seconds, to allow the other thread to race with this thread.
64
+ @result_queue << :t1_committed
62
65
  end
66
+ end
63
67
 
64
- def thread2_main(signal_queue, options={})
65
- Entry.transaction do
66
- signal_queue.shift # wait until we get the signal from thread1
67
- @result_queue << :t2_locking_row1
68
- Entry.find(@row1_id, {:lock=>true}.merge(options)) # should return immediately
69
- @result_queue << :t2_locked_row1
70
- @result_queue << :t2_locking_row2
71
- Entry.find(@row2_id, {:lock=>true}.merge(options)) # should block until thread1 commits its transaction
72
- @result_queue << :t2_locked_row2
73
- @result_queue << :t2_committed
74
- end
68
+ def thread2_main(signal_queue, options={})
69
+ Entry.transaction do
70
+ signal_queue.shift # wait until we get the signal from thread1
71
+ @result_queue << :t2_locking_row1
72
+ Entry.find(@row1_id, {:lock=>true}.merge(options)) # should return immediately
73
+ @result_queue << :t2_locked_row1
74
+ @result_queue << :t2_locking_row2
75
+ Entry.find(@row2_id, {:lock=>true}.merge(options)) # should block until thread1 commits its transaction
76
+ @result_queue << :t2_locked_row2
77
+ @result_queue << :t2_committed
75
78
  end
79
+ end
76
80
 
77
- def thread_helper
78
- yield
79
- rescue Exception => exc
80
- # Output backtrace, since otherwise we won't see anything until the main thread joins this thread.
81
- display_exception(exc)
82
- raise
83
- ensure
84
- # This is needed. Otherwise, the database connections aren't returned to the pool and things break.
85
- ActiveRecord::Base.connection_handler.clear_active_connections!
86
- end
81
+ def thread_helper
82
+ yield
83
+ rescue Exception => exc
84
+ # Output backtrace, since otherwise we won't see anything until the main thread joins this thread.
85
+ display_exception(exc)
86
+ raise
87
+ ensure
88
+ # This is needed. Otherwise, the database connections aren't returned to the pool and things break.
89
+ ActiveRecord::Base.connection_handler.clear_active_connections!
90
+ end
87
91
 
88
- def display_exception(exception)
89
- lines = []
90
- lines << "#{exception.class.name}: #{exception.message}\n"
91
- lines += exception.backtrace.map{|line| "\tfrom #{line}"}
92
- $stderr.puts lines.join("\n")
93
- end
92
+ def display_exception(exception)
93
+ lines = []
94
+ lines << "#{exception.class.name}: #{exception.message}\n"
95
+ lines += exception.backtrace.map{|line| "\tfrom #{line}"}
96
+ $stderr.puts lines.join("\n")
97
+ end
98
+
94
99
  end
@@ -0,0 +1,168 @@
1
+ require 'stringio'
2
+ require 'active_record/schema_dumper'
3
+
4
+ module SchemaDumpTestMethods
5
+ include MigrationSetup
6
+
7
+ def test_dumping_schema_with_index
8
+ connection = ActiveRecord::Base.connection
9
+ connection.add_index :entries, :title
10
+ StringIO.open do |io|
11
+ ActiveRecord::SchemaDumper.dump(connection, io)
12
+ assert_match(/add_index "entries",/, io.string)
13
+ end
14
+ ensure
15
+ connection.remove_index :entries, :title
16
+ end
17
+
18
+ def standard_dump(io = StringIO.new, ignore_tables = [])
19
+ io = StringIO.new
20
+ ActiveRecord::SchemaDumper.ignore_tables = ignore_tables
21
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, io)
22
+ io.string
23
+ end
24
+ private :standard_dump
25
+
26
+ def test_magic_comment
27
+ standard_dump(strio = StringIO.new)
28
+ assert_match "# encoding: #{strio.external_encoding.name}", standard_dump
29
+ end if ( "string".encoding_aware? rescue nil )
30
+
31
+ def test_schema_dump
32
+ output = standard_dump
33
+ assert_match %r{create_table "users"}, output
34
+ assert_match %r{create_table "entries"}, output
35
+ assert_no_match %r{create_table "schema_migrations"}, output
36
+ end
37
+
38
+ def test_schema_dump_excludes_sqlite_sequence
39
+ output = standard_dump
40
+ assert_no_match %r{create_table "sqlite_sequence"}, output
41
+ end
42
+
43
+ def assert_line_up(lines, pattern, required = false)
44
+ return assert(true) if lines.empty?
45
+ matches = lines.map { |line| line.match(pattern) }
46
+ assert matches.all? if required
47
+ matches.compact!
48
+ return assert(true) if matches.empty?
49
+ assert_equal 1, matches.map{ |match| match.offset(0).first }.uniq.length
50
+ end
51
+
52
+ def column_definition_lines(output = standard_dump)
53
+ output.scan(/^( *)create_table.*?\n(.*?)^\1end/m).map{ |m| m.last.split(/\n/) }
54
+ end
55
+ private :column_definition_lines
56
+
57
+ def test_types_line_up
58
+ column_definition_lines.each do |column_set|
59
+ next if column_set.empty?
60
+
61
+ lengths = column_set.map do |column|
62
+ if match = column.match(/t\.(?:integer|decimal|float|datetime|timestamp|time|date|text|binary|string|boolean)\s+"/)
63
+ match[0].length
64
+ end
65
+ end
66
+
67
+ assert_equal 1, lengths.uniq.length
68
+ end
69
+ end
70
+
71
+ def test_arguments_line_up
72
+ column_definition_lines.each do |column_set|
73
+ assert_line_up(column_set, /:default => /)
74
+ assert_line_up(column_set, /:limit => /)
75
+ assert_line_up(column_set, /:null => /)
76
+ end
77
+ end
78
+
79
+ def test_no_dump_errors
80
+ output = standard_dump
81
+ assert_no_match %r{\# Could not dump table}, output
82
+ end
83
+
84
+ def test_schema_dump_includes_not_null_columns
85
+ output = standard_dump(StringIO.new, [/^[^u]/]) # keep users
86
+ assert_match %r{:null => false}, output
87
+ end
88
+
89
+ def test_schema_dump_with_string_ignored_table
90
+ stream = StringIO.new
91
+
92
+ ActiveRecord::SchemaDumper.ignore_tables = ['users']
93
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
94
+ output = stream.string
95
+ assert_no_match %r{create_table "users"}, output
96
+ assert_match %r{create_table "entries"}, output
97
+ assert_no_match %r{create_table "schema_migrations"}, output
98
+ end
99
+
100
+ def test_schema_dump_with_regexp_ignored_table
101
+ output = standard_dump(StringIO.new, [/^user/]) # ignore users
102
+ assert_no_match %r{create_table "users"}, output
103
+ assert_match %r{create_table "entries"}, output
104
+ assert_no_match %r{create_table "schema_migrations"}, output
105
+ end
106
+
107
+ def test_schema_dump_should_honor_nonstandard_primary_keys
108
+ output = standard_dump
109
+ match = output.match(%r{create_table "custom_pk_names"(.*)do})
110
+ assert_not_nil(match, "nonstandardpk table not found")
111
+ assert_match %r(:primary_key => "custom_id"), match[1], "non-standard primary key not preserved"
112
+ end
113
+
114
+ def test_schema_dump_includes_decimal_options
115
+ output = standard_dump(StringIO.new, [/^[^d]/]) # keep db_types
116
+ # t.column :sample_small_decimal, :decimal, :precision => 3, :scale => 2, :default => 3.14
117
+ assert_match %r{:precision => 3,[[:space:]]+:scale => 2,[[:space:]]+:default => 3.14}, output
118
+ end
119
+
120
+ def test_schema_dump_keeps_large_precision_integer_columns_as_decimal
121
+ output = standard_dump
122
+ precision = DbTypeMigration.big_decimal_precision
123
+ assert_match %r{t.decimal\s+"big_decimal",\s+:precision => #{precision},\s+:scale => 0}, output
124
+ end if Test::Unit::TestCase.ar_version('3.0') # does not work in 2.3 :
125
+ # t.integer "big_decimal", :limit => 38, :precision => 38, :scale => 0
126
+
127
+ def test_schema_dump_keeps_id_column_when_id_is_false_and_id_column_added
128
+ output = standard_dump
129
+ match = output.match(%r{create_table "string_ids"(.*)do.*\n(.*)\n})
130
+ assert_not_nil(match, "string_ids table not found")
131
+ assert_match %r(:id => false), match[1], "no table id not preserved"
132
+ assert_match %r{t.string[[:space:]]+"id",[[:space:]]+:null => false$}, match[2], "non-primary key id column not preserved"
133
+ end
134
+
135
+ def test_schema_dump_keeps_id_false_when_id_is_false_and_unique_not_null_column_added
136
+ output = standard_dump
137
+ assert_match %r{create_table "things", :id => false}, output
138
+ end
139
+
140
+ class CreateDogMigration < ActiveRecord::Migration
141
+ def up
142
+ create_table :dogs do |t|
143
+ t.column :name, :string
144
+ end
145
+ end
146
+ def down
147
+ drop_table :dogs
148
+ end
149
+ end
150
+
151
+ def test_schema_dump_with_table_name_prefix_and_suffix
152
+ ActiveRecord::Base.table_name_prefix = 'foo_'
153
+ ActiveRecord::Base.table_name_suffix = '_bar'
154
+
155
+ migration = CreateDogMigration.new
156
+ migration.migrate(:up)
157
+
158
+ output = standard_dump
159
+ assert_no_match %r{create_table "foo_.+_bar"}, output
160
+ assert_no_match %r{create_index "foo_.+_bar"}, output
161
+ assert_no_match %r{create_table "schema_migrations"}, output
162
+ ensure
163
+ migration.migrate(:down)
164
+
165
+ ActiveRecord::Base.table_name_suffix = ActiveRecord::Base.table_name_prefix = ''
166
+ end if Test::Unit::TestCase.ar_version('3.2')
167
+
168
+ end
@@ -0,0 +1,277 @@
1
+ require 'models/topic'
2
+ require 'ostruct'
3
+
4
+ # borrosed from AR/test/cases/serialized_attribute_test.rb
5
+
6
+ module SerializeTestMethods
7
+
8
+ def self.included(base)
9
+ base.extend UpAndDown
10
+ end
11
+
12
+ module UpAndDown
13
+
14
+ def startup
15
+ super
16
+ TopicMigration.up
17
+ end
18
+
19
+ def shutdown
20
+ super
21
+ TopicMigration.down
22
+ end
23
+
24
+ end
25
+
26
+ def setup
27
+ super
28
+ end
29
+
30
+ def teardown
31
+ super
32
+ Topic.serialize("content")
33
+ end
34
+
35
+ MyObject = Struct.new :attribute1, :attribute2
36
+
37
+ def test_list_of_serialized_attributes
38
+ assert_equal %w(content), Topic.serialized_attributes.keys
39
+ end
40
+
41
+ def test_serialized_attribute
42
+ Topic.serialize("content", MyObject)
43
+
44
+ myobj = MyObject.new('value1', 'value2')
45
+ topic = Topic.create("content" => myobj)
46
+ assert_equal(myobj, topic.content)
47
+
48
+ topic.reload
49
+ assert_equal(myobj, topic.content)
50
+ end
51
+
52
+ def test_serialized_attribute_init_with
53
+ topic = Topic.allocate
54
+ topic.init_with('attributes' => { 'content' => '--- foo' })
55
+ assert_equal 'foo', topic.content
56
+ end if Test::Unit::TestCase.ar_version('3.0')
57
+
58
+ def test_serialized_attribute_in_base_class
59
+ Topic.serialize("content", Hash)
60
+
61
+ hash = { 'content1' => 'value1', 'content2' => 'value2' }
62
+ important_topic = ImportantTopic.create("content" => hash)
63
+ assert_equal(hash, important_topic.content)
64
+
65
+ important_topic.reload
66
+ assert_equal(hash, important_topic.content)
67
+ end
68
+
69
+ # This test was added to fix GH #4004. Obviously the value returned
70
+ # is not really the value 'before type cast' so we should maybe think
71
+ # about changing that in the future.
72
+ # def test_serialized_attribute_before_type_cast_returns_unserialized_value
73
+ # Topic.serialize :content, Hash
74
+ #
75
+ # t = Topic.new :content => { :foo => :bar }
76
+ # assert_equal({ :foo => :bar }, t.content_before_type_cast)
77
+ # t.save!
78
+ # t.reload
79
+ # assert_equal({ :foo => :bar }, t.content_before_type_cast)
80
+ # end
81
+
82
+ # def test_serialized_attributes_before_type_cast_returns_unserialized_value
83
+ # Topic.serialize :content, Hash
84
+ #
85
+ # t = Topic.new :content => { :foo => :bar }
86
+ # assert_equal({ :foo => :bar }, t.attributes_before_type_cast["content"])
87
+ # t.save!
88
+ # t.reload
89
+ # assert_equal({ :foo => :bar }, t.attributes_before_type_cast["content"])
90
+ # end
91
+
92
+ def test_serialized_ostruct
93
+ Topic.serialize :content, OpenStruct
94
+
95
+ t = Topic.new
96
+ t.content.foo = 'bar'
97
+ t.save!
98
+ assert_equal 'bar', t.reload.content.foo
99
+ end if Test::Unit::TestCase.ar_version('3.1')
100
+
101
+ def test_serialized_attribute_declared_in_subclass
102
+ hash = { 'important1' => 'value1', 'important2' => 'value2' }
103
+ important_topic = ImportantTopic.create("important" => hash)
104
+ assert_equal(hash, important_topic.important)
105
+
106
+ important_topic.reload
107
+ assert_equal(hash, important_topic.important)
108
+ assert_equal(hash, important_topic.read_attribute(:important))
109
+ end
110
+
111
+ def test_serialized_time_attribute
112
+ myobj = Time.local(2008,1,1,1,0)
113
+ topic = Topic.create("content" => myobj).reload
114
+ assert_equal(myobj, topic.content)
115
+ end
116
+
117
+ def test_serialized_string_attribute
118
+ myobj = "Yes"
119
+ topic = Topic.create("content" => myobj).reload
120
+ assert_equal(myobj, topic.content)
121
+ end
122
+
123
+ def test_nil_serialized_attribute_with_class_constraint
124
+ topic = ImportantTopic.new
125
+ assert_nil topic.content
126
+ end
127
+
128
+ def test_nil_serialized_attribute_without_class_constraint
129
+ topic = Topic.new
130
+ assert_nil topic.content
131
+ end
132
+
133
+ def test_nil_not_serialized_without_class_constraint
134
+ #ActiveRecord::Base.logger.level = Logger::DEBUG
135
+ topic = Topic.new(:content => nil); topic.save!
136
+ # NOTE: seems smt broken on AR 3.2's side inserts '--- \n' !
137
+ #assert_equal 1, Topic.where(:content => nil).count
138
+ assert_nil topic.reload.content
139
+ ensure
140
+ #ActiveRecord::Base.logger.level = Logger::WARN
141
+ end
142
+
143
+ def test_nil_not_serialized_with_class_constraint
144
+ #ActiveRecord::Base.logger.level = Logger::DEBUG
145
+ topic = ImportantTopic.new(:content => nil); topic.save!
146
+ # NOTE: seems smt broken on AR 3.2's side inserts '--- \n' !
147
+ #assert_equal 1, ImportantTopic.where(:content => nil).count
148
+ assert_nil topic.reload.content
149
+ ensure
150
+ #ActiveRecord::Base.logger.level = Logger::WARN
151
+ end
152
+
153
+ def test_serialized_attribute_should_raise_exception_on_save_with_wrong_type
154
+ Topic.serialize(:content, Hash)
155
+ topic = Topic.new(:content => "string")
156
+ assert_raise(ActiveRecord::SerializationTypeMismatch) { topic.save }
157
+ end if Test::Unit::TestCase.ar_version('3.2')
158
+
159
+ def test_should_raise_exception_on_serialized_attribute_with_type_mismatch
160
+ myobj = MyObject.new('value1', 'value2')
161
+ topic = Topic.new(:content => myobj)
162
+ assert topic.save
163
+ Topic.serialize(:content, Hash)
164
+ assert_raise(ActiveRecord::SerializationTypeMismatch) { Topic.find(topic.id).content }
165
+ end if Test::Unit::TestCase.ar_version('3.2')
166
+
167
+ def test_serialized_attribute_with_class_constraint
168
+ settings = { "color" => "blue" }
169
+ Topic.serialize(:content, Hash)
170
+ topic = Topic.new(:content => settings)
171
+ assert topic.save
172
+ assert_equal(settings, Topic.find(topic.id).content)
173
+ end
174
+
175
+ def test_serialized_default_class
176
+ Topic.serialize(:content, Hash)
177
+ topic = Topic.new
178
+ assert_equal Hash, topic.content.class
179
+ assert_equal Hash, topic.read_attribute(:content).class
180
+ topic.content["beer"] = "MadridRb"
181
+ assert topic.save
182
+ topic.reload
183
+ assert_equal Hash, topic.content.class
184
+ assert_equal "MadridRb", topic.content["beer"]
185
+ end if Test::Unit::TestCase.ar_version('3.1')
186
+
187
+ def test_serialized_no_default_class_for_object
188
+ topic = Topic.new
189
+ assert_nil topic.content
190
+ end
191
+
192
+ def test_serialized_boolean_value_true
193
+ Topic.serialize(:content)
194
+ topic = Topic.new(:content => true)
195
+ assert topic.save
196
+ topic = topic.reload
197
+ assert_equal topic.content, true
198
+ end if Test::Unit::TestCase.ar_version('3.0')
199
+
200
+ def test_serialized_boolean_value_false
201
+ Topic.serialize(:content)
202
+ topic = Topic.new(:content => false)
203
+ assert topic.save
204
+ topic = topic.reload
205
+ assert_equal topic.content, false
206
+ end if Test::Unit::TestCase.ar_version('3.0')
207
+
208
+ def test_serialize_with_coder
209
+ coder = Class.new {
210
+ # Identity
211
+ def load(thing)
212
+ thing
213
+ end
214
+
215
+ # base 64
216
+ def dump(thing)
217
+ [thing].pack('m')
218
+ end
219
+ }.new
220
+
221
+ Topic.serialize(:content, coder)
222
+ s = 'hello world'
223
+ topic = Topic.new(:content => s)
224
+ assert topic.save
225
+ topic = topic.reload
226
+ assert_equal [s].pack('m'), topic.content
227
+ ensure
228
+ Topic.serialize(:content)
229
+ end if Test::Unit::TestCase.ar_version('3.1')
230
+
231
+ def test_serialize_with_bcrypt_coder
232
+ require 'bcrypt'
233
+ crypt_coder = Class.new {
234
+ def load(thing)
235
+ return unless thing
236
+ BCrypt::Password.new thing
237
+ end
238
+
239
+ def dump(thing)
240
+ BCrypt::Password.create(thing).to_s
241
+ end
242
+ }.new
243
+
244
+ Topic.serialize(:content, crypt_coder)
245
+ password = 'password'
246
+ topic = Topic.new(:content => password)
247
+ assert topic.save
248
+ topic = topic.reload
249
+ assert_kind_of BCrypt::Password, topic.content
250
+ assert_equal(true, topic.content == password, 'password should equal')
251
+ end if Test::Unit::TestCase.ar_version('3.1')
252
+
253
+ def test_serialize_attribute_via_select_method_when_time_zone_available
254
+ ActiveRecord::Base.time_zone_aware_attributes = true
255
+ Topic.serialize(:content, MyObject)
256
+
257
+ myobj = MyObject.new('value1', 'value2')
258
+ topic = Topic.create(:content => myobj)
259
+
260
+ ActiveRecord::IdentityMap.without do
261
+ assert_equal(myobj, Topic.select(:content).find(topic.id).content)
262
+ assert_raise(ActiveModel::MissingAttributeError) { Topic.select(:id).find(topic.id).content }
263
+ end
264
+ ensure
265
+ ActiveRecord::Base.time_zone_aware_attributes = false
266
+ end if Test::Unit::TestCase.ar_version('3.2')
267
+
268
+ # def test_serialize_attribute_can_be_serialized_in_an_integer_column
269
+ # insures = ['life']
270
+ # person = SerializedPerson.new(:first_name => 'David', :insures => insures)
271
+ # assert person.save
272
+ # person = person.reload
273
+ # assert_equal(insures, person.insures)
274
+ # end
275
+
276
+ end
277
+