activerecord-cockroachdb-adapter 8.0.2 → 8.1.0

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 (239) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/CONTRIBUTING.md +10 -17
  4. data/Gemfile +2 -1
  5. data/Rakefile +0 -19
  6. data/lib/active_record/connection_adapters/cockroachdb/column.rb +66 -24
  7. data/lib/active_record/connection_adapters/cockroachdb/database_statements.rb +13 -3
  8. data/lib/active_record/connection_adapters/cockroachdb/database_tasks.rb +1 -1
  9. data/lib/active_record/connection_adapters/cockroachdb/oid/spatial.rb +34 -19
  10. data/lib/active_record/connection_adapters/cockroachdb/quoting.rb +19 -3
  11. data/lib/active_record/connection_adapters/cockroachdb/referential_integrity.rb +87 -55
  12. data/lib/active_record/connection_adapters/cockroachdb/schema_statements.rb +181 -102
  13. data/lib/active_record/connection_adapters/cockroachdb_adapter.rb +42 -25
  14. data/lib/version.rb +1 -1
  15. data/test/cases/adapter_test.rb +98 -0
  16. data/test/cases/adapters/cockroachdb/referential_integrity_test.rb +51 -0
  17. data/test/cases/adapters/postgresql/active_schema_test.rb +71 -0
  18. data/test/cases/adapters/postgresql/change_schema_test.rb +75 -0
  19. data/test/cases/adapters/postgresql/connection_test.rb +46 -0
  20. data/test/cases/adapters/postgresql/ddl_test.rb +326 -0
  21. data/test/cases/adapters/postgresql/interval_test.rb +131 -0
  22. data/test/cases/adapters/postgresql/nested_class_test.rb +22 -0
  23. data/test/cases/adapters/postgresql/numeric_test.rb +28 -0
  24. data/test/cases/adapters/postgresql/postgis_test.rb +185 -0
  25. data/test/cases/adapters/postgresql/postgresql_adapter_test.rb +115 -0
  26. data/test/cases/adapters/postgresql/quoting_test.rb +30 -0
  27. data/test/cases/adapters/postgresql/schema_statements_test.rb +29 -0
  28. data/test/cases/adapters/postgresql/serial_test.rb +199 -0
  29. data/test/cases/adapters/postgresql/spatial_queries_test.rb +118 -0
  30. data/test/cases/adapters/postgresql/spatial_setup_test.rb +18 -0
  31. data/test/cases/adapters/postgresql/spatial_type_test.rb +41 -0
  32. data/test/cases/adapters/postgresql/timestamp_test.rb +58 -0
  33. data/test/cases/adapters/postgresql/virtual_column_test.rb +39 -0
  34. data/test/cases/associations/eager_load_nested_include_test.rb +111 -0
  35. data/test/cases/associations/left_outer_join_association_test.rb +30 -0
  36. data/test/cases/associations_test.rb +108 -0
  37. data/test/cases/base_test.rb +31 -0
  38. data/test/cases/comment_test.rb +75 -0
  39. data/test/cases/connection_adapters/type_test.rb +28 -0
  40. data/test/cases/database_configurations/resolver_test.rb +24 -0
  41. data/test/cases/defaults_test.rb +45 -0
  42. data/test/cases/dirty_test.rb +24 -0
  43. data/test/cases/fixtures_test.rb +541 -0
  44. data/test/cases/helper_cockroachdb.rb +232 -0
  45. data/test/cases/inheritance_test.rb +42 -0
  46. data/test/cases/invertible_migration_test.rb +73 -0
  47. data/test/cases/marshal_serialization_test.rb +45 -0
  48. data/test/cases/migration/change_schema_test.rb +140 -0
  49. data/test/cases/migration/check_constraint_test.rb +125 -0
  50. data/test/cases/migration/columns_test.rb +50 -0
  51. data/test/cases/migration/create_join_table_test.rb +66 -0
  52. data/test/cases/migration/foreign_key_test.rb +390 -0
  53. data/test/cases/migration/hidden_column_test.rb +70 -0
  54. data/test/cases/migration/references_foreign_key_test.rb +124 -0
  55. data/test/cases/migration_test.rb +120 -0
  56. data/test/cases/persistence_test.rb +33 -0
  57. data/test/cases/primary_keys_test.rb +134 -0
  58. data/test/cases/relation/aost_test.rb +57 -0
  59. data/test/cases/relation/or_test.rb +26 -0
  60. data/test/cases/relation/table_hints_test.rb +124 -0
  61. data/test/cases/relation_test.rb +26 -0
  62. data/test/cases/relations_test.rb +29 -0
  63. data/test/cases/schema_dumper_test.rb +221 -0
  64. data/test/cases/show_create_test.rb +14 -0
  65. data/test/cases/strict_loading_test.rb +34 -0
  66. data/test/cases/tasks/cockroachdb_rake_test.rb +113 -0
  67. data/test/cases/test_fixtures_test.rb +57 -0
  68. data/test/cases/transactions_test.rb +51 -0
  69. data/test/cases/unsafe_raw_sql_test.rb +22 -0
  70. data/test/config.yml +23 -0
  71. data/test/excludes/ActiveRecord/AdapterTest.rb +3 -0
  72. data/test/excludes/ActiveRecord/AdapterTestWithoutTransaction.rb +25 -0
  73. data/test/excludes/ActiveRecord/ConnectionAdapters/PoolConfig/ResolverTest.rb +1 -0
  74. data/test/excludes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapter/BindParameterTest.rb +15 -0
  75. data/test/excludes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapter/QuotingTest.rb +22 -0
  76. data/test/excludes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapterPreventWritesLegacyTest.rb +1 -0
  77. data/test/excludes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapterPreventWritesTest.rb +1 -0
  78. data/test/excludes/ActiveRecord/ConnectionAdapters/PostgreSQLAdapterTest.rb +40 -0
  79. data/test/excludes/ActiveRecord/ConnectionAdapters/RegistrationIsolatedTest.rb +14 -0
  80. data/test/excludes/ActiveRecord/Encryption/EncryptionPerformanceTest.rb +1 -0
  81. data/test/excludes/ActiveRecord/Encryption/EnvelopeEncryptionPerformanceTest.rb +1 -0
  82. data/test/excludes/ActiveRecord/Encryption/ExtendedDeterministicQueriesPerformanceTest.rb +1 -0
  83. data/test/excludes/ActiveRecord/Encryption/StoragePerformanceTest.rb +2 -0
  84. data/test/excludes/ActiveRecord/InstrumentationTest.rb +16 -0
  85. data/test/excludes/ActiveRecord/InvertibleMigrationTest.rb +2 -0
  86. data/test/excludes/ActiveRecord/Migration/ChangeSchemaTest.rb +7 -0
  87. data/test/excludes/ActiveRecord/Migration/CheckConstraintTest.rb +6 -0
  88. data/test/excludes/ActiveRecord/Migration/ColumnsTest.rb +4 -0
  89. data/test/excludes/ActiveRecord/Migration/CompatibilityTest.rb +50 -0
  90. data/test/excludes/ActiveRecord/Migration/CompositeForeignKeyTest.rb +2 -0
  91. data/test/excludes/ActiveRecord/Migration/CreateJoinTableTest.rb +2 -0
  92. data/test/excludes/ActiveRecord/Migration/ForeignKeyInCreateTest.rb +1 -0
  93. data/test/excludes/ActiveRecord/Migration/ForeignKeyTest.rb +35 -0
  94. data/test/excludes/ActiveRecord/Migration/InvalidOptionsTest.rb +14 -0
  95. data/test/excludes/ActiveRecord/Migration/PGChangeSchemaTest.rb +8 -0
  96. data/test/excludes/ActiveRecord/Migration/ReferencesForeignKeyTest.rb +7 -0
  97. data/test/excludes/ActiveRecord/Migration/ReferencesIndexTest.rb +7 -0
  98. data/test/excludes/ActiveRecord/Migration/ReferencesStatementsTest.rb +3 -0
  99. data/test/excludes/ActiveRecord/MysqlDBCreateWithInvalidPermissionsTest.rb +1 -0
  100. data/test/excludes/ActiveRecord/OrTest.rb +1 -0
  101. data/test/excludes/ActiveRecord/PostgreSQLStructureDumpTest.rb +10 -0
  102. data/test/excludes/ActiveRecord/PostgresqlConnectionTest.rb +12 -0
  103. data/test/excludes/ActiveRecord/PostgresqlTransactionNestedTest.rb +14 -0
  104. data/test/excludes/ActiveRecord/PostgresqlTransactionTest.rb +4 -0
  105. data/test/excludes/ActiveRecord/RelationTest.rb +2 -0
  106. data/test/excludes/ActiveRecord/TooManyOrTest.rb +1 -0
  107. data/test/excludes/ActiveSupportSubclassWithFixturesTest.rb +1 -0
  108. data/test/excludes/AssociationDeprecationTest/NotifyModeTest.rb +2 -0
  109. data/test/excludes/AssociationDeprecationTest/RaiseBacktraceModeTest.rb +2 -0
  110. data/test/excludes/AssociationDeprecationTest/RaiseModeTest.rb +2 -0
  111. data/test/excludes/AssociationDeprecationTest/WarnBacktraceModeTest.rb +2 -0
  112. data/test/excludes/AssociationDeprecationTest/WarnModeTest.rb +2 -0
  113. data/test/excludes/AssociationDeprecationTest/fix_backtrace_cleaner.rb +10 -0
  114. data/test/excludes/BasicsTest.rb +1 -0
  115. data/test/excludes/BulkAlterTableMigrationsTest.rb +7 -0
  116. data/test/excludes/CalculationsTest.rb +4 -0
  117. data/test/excludes/CommentTest.rb +2 -0
  118. data/test/excludes/CoreTest.rb +1 -0
  119. data/test/excludes/CreateOrFindByWithinTransactions.rb +3 -0
  120. data/test/excludes/DefaultsUsingMultipleSchemasAndDomainTest.rb +7 -0
  121. data/test/excludes/DirtyTest.rb +3 -0
  122. data/test/excludes/EachTest.rb +8 -0
  123. data/test/excludes/EagerLoadPolyAssocsTest.rb +1 -0
  124. data/test/excludes/ExplicitlyNamedIndexMigrationTest.rb +1 -0
  125. data/test/excludes/FixturesResetPkSequenceTest.rb +3 -0
  126. data/test/excludes/FixturesTest.rb +21 -0
  127. data/test/excludes/FixturesWithForeignKeyViolationsTest.rb +2 -0
  128. data/test/excludes/ForeignTableTest.rb +10 -0
  129. data/test/excludes/InheritanceComputeTypeTest.rb +1 -0
  130. data/test/excludes/LeftOuterJoinAssociationTest.rb +2 -0
  131. data/test/excludes/LegacyPrimaryKeyTest/V4_2.rb +6 -0
  132. data/test/excludes/LegacyPrimaryKeyTest/V5_0.rb +6 -0
  133. data/test/excludes/MarshalSerializationTest.rb +4 -0
  134. data/test/excludes/MaterializedViewTest.rb +13 -0
  135. data/test/excludes/MigrationTest.rb +2 -0
  136. data/test/excludes/MultiDbMigratorTest.rb +2 -0
  137. data/test/excludes/NestedRelationScopingTest.rb +1 -0
  138. data/test/excludes/OrTest.rb +1 -0
  139. data/test/excludes/PersistenceTest.rb +3 -0
  140. data/test/excludes/PessimisticLockingTest.rb +1 -0
  141. data/test/excludes/PostgreSQLExplainTest.rb +7 -0
  142. data/test/excludes/PostgreSQLGeometricLineTest.rb +3 -0
  143. data/test/excludes/PostgreSQLGeometricTypesTest.rb +7 -0
  144. data/test/excludes/PostgreSQLPartitionsTest.rb +1 -0
  145. data/test/excludes/PostgreSQLReferentialIntegrityTest.rb +14 -0
  146. data/test/excludes/PostgresqlArrayTest.rb +21 -0
  147. data/test/excludes/PostgresqlBigSerialTest.rb +7 -0
  148. data/test/excludes/PostgresqlBitStringTest.rb +2 -0
  149. data/test/excludes/PostgresqlByteaTest.rb +1 -0
  150. data/test/excludes/PostgresqlCitextTest.rb +7 -0
  151. data/test/excludes/PostgresqlCollationTest.rb +5 -0
  152. data/test/excludes/PostgresqlCompositeTest.rb +2 -0
  153. data/test/excludes/PostgresqlCompositeWithCustomOIDTest.rb +2 -0
  154. data/test/excludes/PostgresqlDataTypeTest.rb +9 -0
  155. data/test/excludes/PostgresqlDefaultExpressionTest.rb +1 -0
  156. data/test/excludes/PostgresqlDeferredConstraintsTest.rb +3 -0
  157. data/test/excludes/PostgresqlDomainTest.rb +2 -0
  158. data/test/excludes/PostgresqlExtensionMigrationTest.rb +5 -0
  159. data/test/excludes/PostgresqlFullTextTest.rb +3 -0
  160. data/test/excludes/PostgresqlGeometricTest.rb +4 -0
  161. data/test/excludes/PostgresqlHstoreTest.rb +45 -0
  162. data/test/excludes/PostgresqlInfinityTest.rb +5 -0
  163. data/test/excludes/PostgresqlIntervalTest.rb +1 -0
  164. data/test/excludes/PostgresqlJSONBTest.rb +27 -0
  165. data/test/excludes/PostgresqlJSONTest.rb +27 -0
  166. data/test/excludes/PostgresqlLtreeTest.rb +4 -0
  167. data/test/excludes/PostgresqlMoneyTest.rb +12 -0
  168. data/test/excludes/PostgresqlNetworkTest.rb +69 -0
  169. data/test/excludes/PostgresqlNumberTest.rb +1 -0
  170. data/test/excludes/PostgresqlPointTest.rb +15 -0
  171. data/test/excludes/PostgresqlRangeTest.rb +3 -0
  172. data/test/excludes/PostgresqlRenameTableTest.rb +2 -0
  173. data/test/excludes/PostgresqlSerialTest.rb +7 -0
  174. data/test/excludes/PostgresqlTimestampFixtureTest.rb +2 -0
  175. data/test/excludes/PostgresqlTimestampMigrationTest.rb +3 -0
  176. data/test/excludes/PostgresqlTypeLookupTest.rb +2 -0
  177. data/test/excludes/PostgresqlUUIDGenerationTest.rb +7 -0
  178. data/test/excludes/PostgresqlUUIDTest.rb +1 -0
  179. data/test/excludes/PostgresqlVirtualColumnTest.rb +17 -0
  180. data/test/excludes/PostgresqlXMLTest.rb +5 -0
  181. data/test/excludes/PrimaryKeyIntegerNilDefaultTest.rb +1 -0
  182. data/test/excludes/PrimaryKeyIntegerTest.rb +3 -0
  183. data/test/excludes/PrimaryKeysTest.rb +2 -0
  184. data/test/excludes/RelationMergingTest.rb +15 -0
  185. data/test/excludes/RelationTest.rb +3 -0
  186. data/test/excludes/ReservedWordsMigrationTest.rb +1 -0
  187. data/test/excludes/SameNameDifferentDatabaseFixturesTest.rb +1 -0
  188. data/test/excludes/SanitizeTest.rb +13 -0
  189. data/test/excludes/SchemaAuthorizationTest.rb +8 -0
  190. data/test/excludes/SchemaCreateTableOptionsTest.rb +2 -0
  191. data/test/excludes/SchemaDumperDefaultsTest.rb +1 -0
  192. data/test/excludes/SchemaDumperTest.rb +11 -0
  193. data/test/excludes/SchemaForeignKeyTest.rb +1 -0
  194. data/test/excludes/SchemaIndexNullsOrderTest.rb +2 -0
  195. data/test/excludes/SchemaIndexOpclassTest.rb +3 -0
  196. data/test/excludes/SchemaTest.rb +49 -0
  197. data/test/excludes/SequenceNameDetectionTestCases/CollidedSequenceNameTest.rb +1 -0
  198. data/test/excludes/SequenceNameDetectionTestCases/LongerSequenceNameDetectionTest.rb +1 -0
  199. data/test/excludes/StrictLoadingFixturesTest.rb +1 -0
  200. data/test/excludes/TestFixturesTest.rb +1 -0
  201. data/test/excludes/TransactionInstrumentationTest.rb +1 -0
  202. data/test/excludes/TransactionIsolationTest.rb +1 -0
  203. data/test/excludes/TypeTest.rb +1 -0
  204. data/test/excludes/UniquenessValidationTest.rb +2 -0
  205. data/test/excludes/UnloggedTablesTest.rb +3 -0
  206. data/test/excludes/UnsafeRawSqlTest.rb +2 -0
  207. data/test/excludes/UpdateableViewTest.rb +5 -0
  208. data/test/excludes/WithAnnotationsTest.rb +6 -0
  209. data/test/models/building.rb +4 -0
  210. data/test/models/spatial_model.rb +5 -0
  211. data/test/schema/cockroachdb_specific_schema.rb +218 -0
  212. data/test/support/copy_cat.rb +83 -0
  213. data/test/support/exclude_from_transactional_tests.rb +33 -0
  214. data/test/support/paths_cockroachdb.rb +46 -0
  215. data/test/support/rake_helpers.rb +37 -0
  216. data/test/support/sql_logger.rb +55 -0
  217. data/test/support/template_creator.rb +114 -0
  218. metadata +422 -34
  219. data/.editorconfig +0 -7
  220. data/.github/issue_template.md +0 -46
  221. data/.github/reproduction_scripts/migrations.rb +0 -60
  222. data/.github/reproduction_scripts/models_and_database.rb +0 -49
  223. data/.github/workflows/ci.yml +0 -96
  224. data/.github/workflows/docker.yml +0 -57
  225. data/.gitignore +0 -18
  226. data/.gitmodules +0 -0
  227. data/activerecord-cockroachdb-adapter.gemspec +0 -38
  228. data/bin/console +0 -36
  229. data/bin/console_schemas/default.rb +0 -11
  230. data/bin/console_schemas/schemas.rb +0 -23
  231. data/bin/setup +0 -8
  232. data/bin/start-cockroachdb +0 -33
  233. data/build/Dockerfile +0 -14
  234. data/build/config.teamcity.yml +0 -31
  235. data/build/local-test.sh +0 -32
  236. data/build/teamcity-test.sh +0 -76
  237. data/docker.sh +0 -35
  238. data/lib/active_record/connection_adapters/cockroachdb/spatial_column_info.rb +0 -60
  239. data/setup.sql +0 -18
@@ -0,0 +1,541 @@
1
+ require "cases/helper_cockroachdb"
2
+
3
+ # Load dependencies from ActiveRecord test suite
4
+ require "cases/helper"
5
+ require "support/connection_helper"
6
+ require "models/account"
7
+ require "models/binary"
8
+ require "models/category"
9
+ require "models/company"
10
+ require "models/computer"
11
+ require "models/course"
12
+ require "models/developer"
13
+ require "models/joke"
14
+ require "models/parrot"
15
+ require "models/pirate"
16
+ require "models/task"
17
+ require "models/topic"
18
+ require "models/traffic_light"
19
+ require "models/treasure"
20
+
21
+ # Hacky tool that searches for table definition code in schema.rb
22
+ # and evals it. Doing this ensure we're always using the latest
23
+ # schema.
24
+ module TableCreator
25
+ def self.create_table_using_test_schema(table_name, connection)
26
+ table_name = table_name.to_sym
27
+ @schema_file ||= SCHEMA_ROOT + "/schema.rb"
28
+ @ast ||= Prism::Translation::Parser.parse_file(@schema_file)
29
+ to_search = [@ast]
30
+ found = nil
31
+ while !to_search.empty?
32
+ node = to_search.shift
33
+ next unless node.is_a?(Parser::AST::Node)
34
+ if node in [:block, [:send, _, :create_table, [:sym, ^table_name], *], *]
35
+ break found = node
36
+ end
37
+ to_search += node.children
38
+ end
39
+ raise "Schema #{table_name.inspect} not found" unless found
40
+ connection.instance_eval(found.location.expression.source)
41
+ end
42
+ end
43
+
44
+ module CockroachDB
45
+ class FixturesTest < ActiveRecord::TestCase
46
+ include ConnectionHelper
47
+ self.use_instantiated_fixtures = true
48
+ self.use_transactional_tests = false
49
+
50
+ # other_topics fixture should not be included here
51
+ fixtures :topics, :developers, :accounts, :tasks, :categories, :funny_jokes, :binaries, :traffic_lights
52
+
53
+ FIXTURES = %w( accounts binaries companies customers
54
+ developers developers_projects entrants
55
+ movies projects subscribers topics tasks )
56
+ MATCH_ATTRIBUTE_NAME = /[a-zA-Z][-\w]*/
57
+
58
+ # Drop and recreate the parrots and treasures tables so they use
59
+ # primary key sequences. After recreating the tables, load their fixtures.
60
+ def before_setup
61
+ conn = ActiveRecord::Base.lease_connection
62
+
63
+ conn.disable_referential_integrity do
64
+ parrots_redefine
65
+ treasures_redefine
66
+ parrots_pirates_redefine
67
+ parrots_treasures_redefine
68
+ end
69
+ ensure
70
+ super
71
+ end
72
+
73
+ def teardown
74
+ Arel::Table.engine = ActiveRecord::Base
75
+ ensure
76
+ super
77
+ end
78
+
79
+ # This replaces the same test that's been excluded from
80
+ # FixturesTest. The test is exactly the same, but the tables
81
+ # under test will have primary key sequences, and the connection is from ActiveRecord::Base.
82
+ # Normally, the primary keys would use CockroachDB's unique_rowid().
83
+ def test_clean_fixtures
84
+ FIXTURES.each do |name|
85
+ fixtures = nil
86
+ assert_nothing_raised { fixtures = create_fixtures(name).first }
87
+ assert_kind_of(ActiveRecord::FixtureSet, fixtures)
88
+ fixtures.each { |_name, fixture|
89
+ fixture.each { |key, value|
90
+ assert_match(MATCH_ATTRIBUTE_NAME, key)
91
+ }
92
+ }
93
+ end
94
+ end
95
+
96
+ class InsertQuerySubscriber
97
+ attr_reader :events
98
+
99
+ def initialize
100
+ @events = []
101
+ end
102
+
103
+ def call(_, _, _, _, values)
104
+ @events << values[:sql] if values[:sql] =~ /INSERT/
105
+ end
106
+ end
107
+
108
+ # This replaces the same test that's been excluded from
109
+ # FixturesTest. The test is exactly the same, but the tables
110
+ # under test will have primary key sequences, and the connection is from ActiveRecord::Base.
111
+ # Normally, the primary keys would use CockroachDB's unique_rowid().
112
+ def test_auto_value_on_primary_key
113
+ fixtures = [
114
+ { "name" => "first", "wheels_count" => 2 },
115
+ { "name" => "second", "wheels_count" => 3 }
116
+ ]
117
+ conn = ActiveRecord::Base.lease_connection
118
+ assert_nothing_raised do
119
+ conn.insert_fixtures_set({ "aircraft" => fixtures }, ["aircraft"])
120
+ end
121
+ result = conn.select_all("SELECT name, wheels_count FROM aircraft ORDER BY id")
122
+ assert_equal fixtures, result.to_a
123
+ end
124
+
125
+ # This replaces the same test that's been excluded from
126
+ # FixturesTest. The test is exactly the same, but the tables
127
+ # under test will have primary key sequences, and the connection is from ActiveRecord::Base.
128
+ # Normally, the primary keys would use CockroachDB's unique_rowid().
129
+ def test_multiple_clean_fixtures
130
+ fixtures_array = nil
131
+ assert_nothing_raised { fixtures_array = create_fixtures(*FIXTURES) }
132
+ assert_kind_of(Array, fixtures_array)
133
+ fixtures_array.each { |fixtures| assert_kind_of(ActiveRecord::FixtureSet, fixtures) }
134
+ end
135
+
136
+ # This replaces the same test that's been excluded from
137
+ # FixturesTest. The test is exactly the same, but the tables
138
+ # under test will have primary key sequences, and the connection is from ActiveRecord::Base.
139
+ # Normally, the primary keys would use CockroachDB's unique_rowid().
140
+ def test_bulk_insert_with_a_multi_statement_query_raises_an_exception_when_any_insert_fails
141
+ require "models/aircraft"
142
+
143
+ assert_equal false, Aircraft.columns_hash["wheels_count"].null
144
+ fixtures = {
145
+ "aircraft" => [
146
+ { "name" => "working_aircrafts", "wheels_count" => 2 },
147
+ { "name" => "broken_aircrafts", "wheels_count" => nil },
148
+ ]
149
+ }
150
+
151
+ assert_no_difference "Aircraft.count" do
152
+ assert_raises(ActiveRecord::NotNullViolation) do
153
+ ActiveRecord::Base.lease_connection.insert_fixtures_set(fixtures)
154
+ end
155
+ end
156
+ end
157
+
158
+ # This replaces the same test that's been excluded from
159
+ # FixturesTest. The test is exactly the same, but the tables
160
+ # under test will have primary key sequences, and the connection is from ActiveRecord::Base.
161
+ # Normally, the primary keys would use CockroachDB's unique_rowid().
162
+ def test_inserts_with_pre_and_suffix
163
+ # Reset cache to make finds on the new table work
164
+ ActiveRecord::FixtureSet.reset_cache
165
+
166
+ ActiveRecord::Base.lease_connection.create_table :prefix_other_topics_suffix do |t|
167
+ t.column :title, :string
168
+ t.column :author_name, :string
169
+ t.column :author_email_address, :string
170
+ t.column :written_on, :datetime
171
+ t.column :bonus_time, :time
172
+ t.column :last_read, :date
173
+ t.column :content, :string
174
+ t.column :approved, :boolean, default: true
175
+ t.column :replies_count, :integer, default: 0
176
+ t.column :parent_id, :integer
177
+ t.column :type, :string, limit: 50
178
+ end
179
+
180
+ # Store existing prefix/suffix
181
+ old_prefix = ActiveRecord::Base.table_name_prefix
182
+ old_suffix = ActiveRecord::Base.table_name_suffix
183
+
184
+ # Set a prefix/suffix we can test against
185
+ ActiveRecord::Base.table_name_prefix = "prefix_"
186
+ ActiveRecord::Base.table_name_suffix = "_suffix"
187
+
188
+ other_topic_klass = Class.new(ActiveRecord::Base) do
189
+ def self.name
190
+ "OtherTopic"
191
+ end
192
+ end
193
+
194
+ topics = [create_fixtures("other_topics")].flatten.first
195
+
196
+ # This checks for a caching problem which causes a bug in the fixtures
197
+ # class-level configuration helper.
198
+ assert_not_nil topics, "Fixture data inserted, but fixture objects not returned from create"
199
+
200
+ first_row = ActiveRecord::Base.lease_connection.select_one("SELECT * FROM prefix_other_topics_suffix WHERE author_name = 'David'")
201
+ assert_not_nil first_row, "The prefix_other_topics_suffix table appears to be empty despite create_fixtures: the row with author_name = 'David' was not found"
202
+ assert_equal("The First Topic", first_row["title"])
203
+
204
+ second_row = ActiveRecord::Base.lease_connection.select_one("SELECT * FROM prefix_other_topics_suffix WHERE author_name = 'Mary'")
205
+ assert_nil(second_row["author_email_address"])
206
+
207
+ assert_equal :prefix_other_topics_suffix, topics.table_name.to_sym
208
+ # This assertion should preferably be the last in the list, because calling
209
+ # other_topic_klass.table_name sets a class-level instance variable
210
+ assert_equal :prefix_other_topics_suffix, other_topic_klass.table_name.to_sym
211
+
212
+ ensure
213
+ # Restore prefix/suffix to its previous values
214
+ ActiveRecord::Base.table_name_prefix = old_prefix
215
+ ActiveRecord::Base.table_name_suffix = old_suffix
216
+
217
+ ActiveRecord::Base.lease_connection.drop_table :prefix_other_topics_suffix, if_exists: true
218
+ end
219
+
220
+ # This replaces the same test that's been excluded from
221
+ # FixturesTest. The test is exactly the same, but the tables
222
+ # under test will have primary key sequences, and the connection is from ActiveRecord::Base.
223
+ # Normally, the primary keys would use CockroachDB's unique_rowid().
224
+ def test_create_symbol_fixtures
225
+ fixtures = ActiveRecord::FixtureSet.create_fixtures(FIXTURES_ROOT, :collections, collections: Course)
226
+
227
+ assert Course.find_by_name("Collection"), "course is not in the database"
228
+ assert fixtures.detect { |f| f.name == "collections" }, "no fixtures named 'collections' in #{fixtures.map(&:name).inspect}"
229
+ end
230
+
231
+ private
232
+
233
+ def parrots_redefine
234
+ Parrot.lease_connection.exec_query("DROP TABLE IF EXISTS parrots_pirates")
235
+ Parrot.lease_connection.exec_query("DROP TABLE IF EXISTS parrots_treasures")
236
+
237
+ Parrot.lease_connection.drop_table :parrots, if_exists: true
238
+
239
+ Parrot.lease_connection.exec_query("CREATE SEQUENCE IF NOT EXISTS parrots_id_seq")
240
+ Parrot.lease_connection.exec_query("
241
+ CREATE TABLE parrots (
242
+ id INT PRIMARY KEY DEFAULT nextval('parrots_id_seq'),
243
+ breed INT DEFAULT 0,
244
+ name VARCHAR NULL,
245
+ color VARCHAR NULL,
246
+ parrot_sti_class VARCHAR NULL,
247
+ killer_id INT8 NULL,
248
+ updated_count INT8 NULL DEFAULT 0:::INT8,
249
+ created_at TIMESTAMP NULL,
250
+ created_on TIMESTAMP NULL,
251
+ updated_at TIMESTAMP NULL,
252
+ updated_on TIMESTAMP NULL
253
+ )
254
+ ")
255
+ end
256
+
257
+ def parrots_pirates_redefine
258
+ Parrot.lease_connection.exec_query("DROP TABLE IF EXISTS parrots_pirates")
259
+ Parrot.lease_connection.exec_query("
260
+ CREATE TABLE parrots_pirates (
261
+ parrot_id INT8 NULL,
262
+ pirate_id INT8 NULL,
263
+ CONSTRAINT fk_parrot_id FOREIGN KEY (parrot_id) REFERENCES parrots(id),
264
+ CONSTRAINT fk_pirate_id FOREIGN KEY (pirate_id) REFERENCES pirates(id)
265
+ )
266
+ ")
267
+ end
268
+
269
+ def treasures_redefine
270
+ Treasure.lease_connection.drop_table :treasures, if_exists: true
271
+
272
+ Treasure.lease_connection.exec_query("CREATE SEQUENCE IF NOT EXISTS treasures_id_seq")
273
+ Treasure.lease_connection.exec_query("
274
+ CREATE TABLE treasures (
275
+ id INT PRIMARY KEY DEFAULT nextval('treasures_id_seq'),
276
+ name VARCHAR NULL,
277
+ type VARCHAR NULL,
278
+ looter_type VARCHAR NULL,
279
+ looter_id INT8 NULL,
280
+ ship_id INT8 NULL
281
+ )
282
+ ")
283
+ end
284
+
285
+ def parrots_treasures_redefine
286
+ Parrot.lease_connection.exec_query("DROP TABLE IF EXISTS parrots_treasures")
287
+ Parrot.lease_connection.exec_query("
288
+ CREATE TABLE parrots_treasures (
289
+ parrot_id INT8 NULL,
290
+ treasure_id INT8 NULL
291
+ )
292
+ ")
293
+ end
294
+ end
295
+
296
+ class FixturesResetPkSequenceTest < ActiveRecord::TestCase
297
+ self.use_transactional_tests = false
298
+
299
+ # Drop and recreate the accounts, companies, and courses tables so they use
300
+ # primary key sequences. After recreating the tables, load their fixtures.
301
+ # We'll do this in a before_setup so we get ahead of
302
+ # ActiveRecord::TestFixtures#before_setup.
303
+ def before_setup
304
+ super
305
+ Account.lease_connection.drop_table :accounts, if_exists: true
306
+ Account.lease_connection.exec_query("CREATE SEQUENCE IF NOT EXISTS accounts_id_seq")
307
+ Account.lease_connection.exec_query("
308
+ CREATE TABLE accounts (
309
+ id BIGINT PRIMARY KEY DEFAULT nextval('accounts_id_seq'),
310
+ created_at timestamp NULL,
311
+ updated_at timestamp NULL,
312
+ firm_id bigint,
313
+ firm_name character varying,
314
+ credit_limit integer,
315
+ status string,
316
+ #{'a' * max_identifier_length} integer
317
+ )
318
+ ")
319
+
320
+ Company.lease_connection.drop_table :companies, if_exists: true
321
+ Company.lease_connection.exec_query("CREATE SEQUENCE IF NOT EXISTS companies_nonstd_seq")
322
+ Company.lease_connection.exec_query("
323
+ CREATE TABLE companies (
324
+ id BIGINT PRIMARY KEY DEFAULT nextval('companies_nonstd_seq'),
325
+ type character varying,
326
+ firm_id bigint,
327
+ firm_name character varying,
328
+ name character varying,
329
+ client_of bigint,
330
+ rating bigint,
331
+ account_id integer,
332
+ description character varying,
333
+ status integer
334
+ )
335
+ ")
336
+
337
+ Course.lease_connection.drop_table :courses, if_exists: true
338
+ Course.lease_connection.exec_query("CREATE SEQUENCE IF NOT EXISTS courses_id_seq")
339
+ Course.lease_connection.exec_query("
340
+ CREATE TABLE courses (
341
+ id INT PRIMARY KEY DEFAULT nextval('courses_id_seq'),
342
+ name character varying,
343
+ college_id integer
344
+ )
345
+ ")
346
+
347
+ self.class.fixtures :accounts
348
+ self.class.fixtures :companies
349
+ self.class.fixtures :courses
350
+ end
351
+
352
+ def setup
353
+ super
354
+ @instances = [Account.new(credit_limit: 50), Company.new(name: "RoR Consulting"), Course.new(name: "Test")]
355
+ ActiveRecord::FixtureSet.reset_cache # make sure tables get reinitialized
356
+ end
357
+
358
+ # Drop the primary key sequences and bring back the original tables.
359
+ def teardown
360
+ super
361
+ Account.lease_connection.drop_table :accounts, if_exists: true
362
+ Account.lease_connection.exec_query("DROP SEQUENCE IF EXISTS accounts_id_seq")
363
+ TableCreator.create_table_using_test_schema(:accounts, Account.lease_connection)
364
+
365
+ Company.lease_connection.drop_table :companies, if_exists: true
366
+ Company.lease_connection.exec_query("DROP SEQUENCE IF EXISTS companies_nonstd_seq CASCADE")
367
+ TableCreator.create_table_using_test_schema(:companies, Company.lease_connection)
368
+ # CockroachDB specific schema addition
369
+ Company.lease_connection.add_index(:companies, [:firm_id, :type], name: "company_include_index", include: [:name, :account_id])
370
+
371
+ Course.lease_connection.drop_table :courses, if_exists: true
372
+ Course.lease_connection.exec_query("DROP SEQUENCE IF EXISTS courses_id_seq")
373
+ TableCreator.create_table_using_test_schema(:courses, Course.lease_connection)
374
+
375
+ recreate_parrots
376
+
377
+ Account.reset_column_information
378
+ Company.reset_column_information
379
+ Course.reset_column_information
380
+ end
381
+
382
+ # This replaces the same test that's been excluded from
383
+ # FixturesResetPkSequenceTest. The test is exactly the same, but the tables
384
+ # under test will have primary key sequences. Normally, the primary keys
385
+ # would use CockroachDB's unique_rowid().
386
+ # See test/excludes/FixturesResetPkSequenceTest.rb
387
+ def test_resets_to_min_pk_with_specified_pk_and_sequence
388
+ @instances.each do |instance|
389
+ model = instance.class
390
+ model.delete_all
391
+ model.lease_connection.reset_pk_sequence!(model.table_name, model.primary_key, model.sequence_name)
392
+
393
+ instance.save!
394
+ assert_equal 1, instance.id, "Sequence reset for #{model.table_name} failed."
395
+ end
396
+ end
397
+
398
+ # This replaces the same test that's been excluded from
399
+ # FixturesResetPkSequenceTest. The test is exactly the same, but the tables
400
+ # under test will have primary key sequences. Normally, the primary keys
401
+ # would use CockroachDB's unique_rowid().
402
+ # See test/excludes/FixturesResetPkSequenceTest.rb
403
+ def test_resets_to_min_pk_with_default_pk_and_sequence
404
+ @instances.each do |instance|
405
+ model = instance.class
406
+ model.delete_all
407
+ model.lease_connection.reset_pk_sequence!(model.table_name)
408
+
409
+ instance.save!
410
+ assert_equal 1, instance.id, "Sequence reset for #{model.table_name} failed."
411
+ end
412
+ end
413
+
414
+ # This replaces the same test that's been excluded from
415
+ # FixturesResetPkSequenceTest. The test is exactly the same, but the tables
416
+ # under test will have primary key sequences. Normally, the primary keys
417
+ # would use CockroachDB's unique_rowid().
418
+ # See test/excludes/FixturesResetPkSequenceTest.rb
419
+ def test_create_fixtures_resets_sequences_when_not_cached
420
+ @instances.each do |instance|
421
+ max_id = create_fixtures(instance.class.table_name).first.fixtures.inject(0) do |_max_id, (_, fixture)|
422
+ fixture_id = fixture["id"].to_i
423
+ fixture_id > _max_id ? fixture_id : _max_id
424
+ end
425
+
426
+ # Clone the last fixture to check that it gets the next greatest id.
427
+ instance.save!
428
+ assert_equal max_id + 1, instance.id, "Sequence reset for #{instance.class.table_name} failed."
429
+ end
430
+ end
431
+
432
+ private
433
+
434
+ def max_identifier_length
435
+ ActiveRecord::Base.lease_connection.index_name_length
436
+ end
437
+
438
+ def recreate_parrots
439
+ conn = ActiveRecord::Base.lease_connection
440
+ conn.disable_referential_integrity do
441
+ conn.drop_table :parrots_pirates, if_exists: true
442
+ conn.drop_table :parrots_treasures, if_exists: true
443
+ conn.drop_table :parrots, if_exists: true
444
+
445
+ TableCreator.create_table_using_test_schema(:parrots, conn)
446
+ TableCreator.create_table_using_test_schema(:parrots_pirates, conn)
447
+ TableCreator.create_table_using_test_schema(:parrots_treasures, conn)
448
+ end
449
+ end
450
+ end
451
+
452
+
453
+ class FkObjectToPointTo < ActiveRecord::Base
454
+ has_many :fk_pointing_to_non_existent_objects
455
+ end
456
+ class FkPointingToNonExistentObject < ActiveRecord::Base
457
+ belongs_to :fk_object_to_point_to
458
+ end
459
+
460
+ class FixturesWithForeignKeyViolationsTest < ActiveRecord::TestCase
461
+ # FIXME
462
+ # Spent a long time trying to debug why this only works when the activerecord fixtures_test is run first.
463
+ # The problem is that the fixture is defined in singular "fk_object_to_point_to"
464
+ # but most fixtures are plural (i.e. "parrots"). In the postgres adapter this is handled properly
465
+ # and it pluralizes the table name in the fixture creation step, but in this adapter that doesn't happen.
466
+ # I tried creating a new fixture that was just the pluralized version of this fk_object_to_point_to,
467
+ # but that still didn't work. I tried playing around with ActiveRecord pluralization
468
+ # settings and that didn't work, so for now I'm just going to skip this.
469
+ #
470
+ # Given that this works when the activerecord tests are run first, it's safe to assume
471
+ # this isn't a bug on our end, but it is flakey and will cause the CI to fail depending on the
472
+ # order of tests.
473
+ self.use_instantiated_fixtures = true
474
+ self.use_transactional_tests = false
475
+
476
+ def before_setup
477
+ skip("This test will pass only if the activerecord fixtures_test.rb file is run. When it's not run there's an issue where the fixture table name is not pluralized.")
478
+ end
479
+
480
+ fixtures :fk_object_to_point_to
481
+
482
+ def setup
483
+ # other tests in this file load the parrots fixture but not the treasure one (see `test_create_fixtures`).
484
+ # this creates FK violations since Parrot and ParrotTreasure records are created.
485
+ # those violations can cause false positives in these tests. since they aren't related to these tests we
486
+ # delete the irrelevant records here (this test is transactional so it's fine).
487
+ Parrot.all.each(&:destroy)
488
+ end
489
+
490
+ def test_raises_fk_violations
491
+ fk_pointing_to_non_existent_object = <<~FIXTURE
492
+ first:
493
+ fk_object_to_point_to: one
494
+ FIXTURE
495
+ File.write(FIXTURES_ROOT + "/fk_pointing_to_non_existent_object.yml", fk_pointing_to_non_existent_object)
496
+
497
+ with_verify_foreign_keys_for_fixtures do
498
+ if current_adapter?(:SQLite3Adapter, :PostgreSQLAdapter, :CockroachDBAdapter)
499
+ assert_raise RuntimeError do
500
+ ActiveRecord::FixtureSet.create_fixtures(FIXTURES_ROOT, ["fk_pointing_to_non_existent_object"])
501
+ end
502
+ else
503
+ assert_nothing_raised do
504
+ ActiveRecord::FixtureSet.create_fixtures(FIXTURES_ROOT, ["fk_pointing_to_non_existent_object"])
505
+ end
506
+ end
507
+ end
508
+
509
+ ensure
510
+ File.delete(FIXTURES_ROOT + "/fk_pointing_to_non_existent_object.yml")
511
+ ActiveRecord::FixtureSet.reset_cache
512
+ end
513
+
514
+ def test_does_not_raise_if_no_fk_violations
515
+ fk_pointing_to_valid_object = <<~FIXTURE
516
+ first:
517
+ fk_object_to_point_to_id: 1
518
+ FIXTURE
519
+ File.write(FIXTURES_ROOT + "/fk_pointing_to_non_existent_object.yml", fk_pointing_to_valid_object)
520
+
521
+ with_verify_foreign_keys_for_fixtures do
522
+ assert_nothing_raised do
523
+ ActiveRecord::FixtureSet.create_fixtures(FIXTURES_ROOT, ["fk_pointing_to_non_existent_object"])
524
+ end
525
+ end
526
+
527
+ ensure
528
+ File.delete(FIXTURES_ROOT + "/fk_pointing_to_non_existent_object.yml")
529
+ ActiveRecord::FixtureSet.reset_cache
530
+ end
531
+
532
+ private
533
+ def with_verify_foreign_keys_for_fixtures
534
+ setting_was = ActiveRecord.verify_foreign_keys_for_fixtures
535
+ ActiveRecord.verify_foreign_keys_for_fixtures = true
536
+ yield
537
+ ensure
538
+ ActiveRecord.verify_foreign_keys_for_fixtures = setting_was
539
+ end
540
+ end
541
+ end