activerecord-cockroachdb-adapter 8.0.3 → 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 +3 -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 +39 -21
  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,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/helper"
4
+ require "support/schema_dumping_helper"
5
+
6
+ module CockroachDB
7
+ class PostgresqlIntervalTest < ActiveRecord::PostgreSQLTestCase
8
+ include SchemaDumpingHelper
9
+
10
+ class IntervalDataType < ActiveRecord::Base
11
+ attribute :legacy_term, :string
12
+ end
13
+
14
+ class DeprecatedIntervalDataType < ActiveRecord::Base; end
15
+
16
+ def setup
17
+ @connection = ActiveRecord::Base.lease_connection
18
+ @connection.transaction do
19
+ @connection.create_table("interval_data_types") do |t|
20
+ t.interval "maximum_term"
21
+ t.interval "minimum_term", precision: 3
22
+ t.interval "default_term", default: "P3Y"
23
+ t.interval "all_terms", array: true
24
+ t.interval "legacy_term"
25
+ end
26
+ end
27
+ @column_max = IntervalDataType.columns_hash["maximum_term"]
28
+ @column_min = IntervalDataType.columns_hash["minimum_term"]
29
+ assert(@column_max.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQLColumn))
30
+ assert(@column_min.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQLColumn))
31
+ assert_nil @column_max.precision
32
+ assert_equal 3, @column_min.precision
33
+ end
34
+
35
+ teardown do
36
+ @connection.execute "DROP TABLE IF EXISTS interval_data_types"
37
+ end
38
+
39
+ IntervalTestCase = Struct.new(:input, :expected)
40
+ def test_postgresql_interval_parser
41
+ tests = [
42
+ IntervalTestCase.new('6 years', 6.year),
43
+ IntervalTestCase.new('6 years 5 mons', 6.year + 5.month),
44
+ IntervalTestCase.new('6 years 5 mons 4 days', 6.year + 5.month + 4.days),
45
+ IntervalTestCase.new('6 years 5 mons 4 days 03:00:00', 6.year + 5.month + 4.days + 3.hours),
46
+ IntervalTestCase.new('6 years 5 mons 4 days 03:02:00', 6.year + 5.month + 4.days + 3.hours + 2.minutes),
47
+ IntervalTestCase.new('6 years 5 mons 4 days 03:02:01',
48
+ 6.year + 5.month + 4.days + 3.hours + 2.minutes + 1.second),
49
+ IntervalTestCase.new('6 years 5 mons 4 days 03:02:01.2',
50
+ 6.year + 5.month + 4.days + 3.hours + 2.minutes + 1.2.seconds)
51
+ ]
52
+ tests.each do |test_case|
53
+ result = ActiveRecord::ConnectionAdapters::CockroachDB::PostgresqlInterval::Parser.parse(test_case.input)
54
+ assert_equal test_case.expected, result
55
+ end
56
+ end
57
+
58
+ def test_postgresql_interval_parser_error
59
+ assert_raises(ActiveRecord::ConnectionAdapters::CockroachDB::PostgresqlInterval::ParseError) do
60
+ test_str = 'This is an invalid interval'
61
+ ActiveRecord::ConnectionAdapters::CockroachDB::PostgresqlInterval::Parser.parse(test_str)
62
+ end
63
+ end
64
+
65
+ def test_column
66
+ assert_equal :interval, @column_max.type
67
+ assert_equal :interval, @column_min.type
68
+ assert_equal "interval", @column_max.sql_type
69
+ assert_equal "interval(3)", @column_min.sql_type
70
+ end
71
+
72
+ def test_simple_interval
73
+ IntervalDataType.create!(
74
+ maximum_term: 6.year + 5.month + 4.days + 3.hours + 2.minutes + 1.seconds
75
+ )
76
+ i = IntervalDataType.last!
77
+ assert_equal "P6Y5M4DT3H2M1S", i.maximum_term.iso8601
78
+ end
79
+
80
+ def test_interval_type
81
+ IntervalDataType.create!(
82
+ maximum_term: 6.year + 5.month + 4.days + 3.hours + 2.minutes + 1.seconds,
83
+ minimum_term: 1.year + 2.month + 3.days + 4.hours + 5.minutes + (6.234567).seconds,
84
+ all_terms: [1.month, 1.year, 1.hour],
85
+ legacy_term: "33 years",
86
+ )
87
+ i = IntervalDataType.last!
88
+
89
+ assert_equal "P6Y5M4DT3H2M1S", i.maximum_term.iso8601
90
+ assert_equal "P1Y2M3DT4H5M6.235S", i.minimum_term.iso8601
91
+ assert_equal "P3Y", i.default_term.iso8601
92
+ assert_equal %w[ P1M P1Y PT1H ], i.all_terms.map(&:iso8601)
93
+
94
+ assert_equal "P33Y", i.legacy_term
95
+ end
96
+
97
+ def test_interval_type_cast_from_invalid_string
98
+ i = IntervalDataType.create!(maximum_term: "1 year 2 minutes")
99
+ i.reload
100
+ assert_nil i.maximum_term
101
+ end
102
+
103
+ def test_interval_type_cast_from_numeric
104
+ i = IntervalDataType.create!(minimum_term: 36000)
105
+ i.reload
106
+ assert_equal "PT10H", i.minimum_term.iso8601
107
+ end
108
+
109
+ def test_interval_type_cast_string_and_numeric_from_user
110
+ i = IntervalDataType.new(maximum_term: "P1YT2M", minimum_term: "PT10H", legacy_term: "P1DT1H")
111
+ assert i.maximum_term.is_a?(ActiveSupport::Duration)
112
+ assert i.legacy_term.is_a?(String)
113
+ assert_equal "P1YT2M", i.maximum_term.iso8601
114
+ assert_equal "PT10H", i.minimum_term.iso8601
115
+ assert_equal "P1DT1H", i.legacy_term
116
+ end
117
+
118
+ def test_average_interval_type
119
+ IntervalDataType.create!([{ maximum_term: 6.years }, { maximum_term: 4.months }])
120
+ value = IntervalDataType.average(:maximum_term)
121
+
122
+ assert_equal 3.years + 2.months, value
123
+ assert_instance_of ActiveSupport::Duration, value
124
+ end
125
+
126
+ def test_schema_dump_with_default_value
127
+ output = dump_table_schema "interval_data_types"
128
+ assert_match %r{t\.interval "default_term", default: "3 years 0 mons 0 days 0 hours 0 minutes 0 seconds"}, output
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cases/helper_cockroachdb'
4
+
5
+ class NestedClassTest < ActiveRecord::PostgreSQLTestCase
6
+ module Foo
7
+ def self.table_name_prefix
8
+ 'foo_'
9
+ end
10
+
11
+ class Bar < ActiveRecord::Base
12
+ end
13
+ end
14
+
15
+ def test_nested_model
16
+ Foo::Bar.lease_connection.create_table(:foo_bars, force: true) do |t|
17
+ t.column 'latlon', :st_point, srid: 3785
18
+ end
19
+ assert_empty Foo::Bar.all
20
+ Foo::Bar.lease_connection.drop_table(:foo_bars)
21
+ end
22
+ end
@@ -0,0 +1,28 @@
1
+ require "cases/helper_cockroachdb"
2
+
3
+ # Load dependencies from ActiveRecord test suite
4
+ require "support/schema_dumping_helper"
5
+
6
+ module CockroachDB
7
+ class PostgresqlNumberTest < ActiveRecord::PostgreSQLTestCase
8
+ include SchemaDumpingHelper
9
+
10
+ class PostgresqlNumber < ActiveRecord::Base; end
11
+
12
+ setup do
13
+ @connection = ActiveRecord::Base.lease_connection
14
+ @connection.create_table("postgresql_numbers", force: true) do |t|
15
+ t.decimal 'decimal_default'
16
+ end
17
+ end
18
+
19
+ teardown do
20
+ @connection.drop_table "postgresql_decimals", if_exists: true
21
+ end
22
+
23
+ def test_decimal_values
24
+ record = PostgresqlNumber.new(decimal_default: 111.222)
25
+ assert_equal record.decimal_default, 111.222
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,185 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/helper_cockroachdb"
4
+ require "models/building"
5
+
6
+ class PostGISTest < ActiveRecord::PostgreSQLTestCase
7
+ def setup
8
+ @connection = ActiveRecord::Base.lease_connection
9
+ end
10
+
11
+ def teardown
12
+ spatial_factory_store.default = nil
13
+ spatial_factory_store.clear
14
+ reset_memoized_spatial_factories
15
+ end
16
+
17
+ def test_postgis_available
18
+ assert_equal postgis_version, @connection.postgis_lib_version
19
+ valid_version = ["2.", "3."].any? { |major_ver| @connection.postgis_lib_version.start_with? major_ver }
20
+ assert valid_version
21
+ end
22
+
23
+ def test_arel_visitor
24
+ visitor = Arel::Visitors::CockroachDB.new(@connection)
25
+ node = RGeo::ActiveRecord::SpatialConstantNode.new("POINT (1.0 2.0)")
26
+ collector = Arel::Collectors::PlainString.new
27
+ visitor.accept(node, collector)
28
+ assert_equal "ST_GeomFromText('POINT (1.0 2.0)')", collector.value
29
+ end
30
+
31
+ def test_arel_visitor_will_not_visit_string
32
+ visitor = Arel::Visitors::CockroachDB.new(@connection)
33
+ node = "POINT (1 2)"
34
+ collector = Arel::Collectors::PlainString.new
35
+
36
+ assert_raises(Arel::Visitors::UnsupportedVisitError) do
37
+ visitor.accept(node, collector)
38
+ end
39
+ end
40
+
41
+ def test_set_and_get_point
42
+ obj = klass.new
43
+ assert_nil obj.coordinates
44
+ obj.coordinates = factory.point(1.0, 2.0)
45
+ assert_equal factory.point(1.0, 2.0), obj.coordinates
46
+ assert_equal 3857, obj.coordinates.srid
47
+ end
48
+
49
+ def test_set_and_get_point_from_wkt
50
+ obj = klass.new
51
+ assert_nil obj.coordinates
52
+ obj.coordinates = "POINT(1 2)"
53
+ assert_equal factory.point(1.0, 2.0), obj.coordinates
54
+ assert_equal 3857, obj.coordinates.srid
55
+ end
56
+
57
+ def test_save_and_load_point
58
+ obj = klass.new
59
+ obj.coordinates = factory.point(1.0, 2.0)
60
+ obj.save!
61
+ id = obj.id
62
+ obj2 = klass.find(id)
63
+ assert_equal factory.point(1.0, 2.0), obj2.coordinates
64
+ assert_equal 3857, obj2.coordinates.srid
65
+ end
66
+
67
+ def test_save_and_load_geographic_point
68
+ obj = klass.new
69
+ obj.latlon = geographic_factory.point(1.0, 2.0)
70
+ obj.save!
71
+ id = obj.id
72
+ obj2 = klass.find(id)
73
+ assert_equal geographic_factory.point(1.0, 2.0), obj2.latlon
74
+ assert_equal 4326, obj2.latlon.srid
75
+ end
76
+
77
+ def test_save_and_load_point_from_wkt
78
+ obj = klass.new
79
+ obj.coordinates = "POINT(1 2)"
80
+ obj.save!
81
+ id = obj.id
82
+ obj2 = klass.find(id)
83
+ assert_equal factory.point(1.0, 2.0), obj2.coordinates
84
+ assert_equal 3857, obj2.coordinates.srid
85
+ end
86
+
87
+ def test_set_point_bad_wkt
88
+ obj = klass.create(coordinates: "POINT (x)")
89
+ assert_nil obj.coordinates
90
+ end
91
+
92
+ def test_set_point_wkt_wrong_type
93
+ assert_raises(ActiveRecord::StatementInvalid) do
94
+ klass.create(coordinates: "LINESTRING(1 2, 3 4, 5 6)")
95
+ end
96
+ end
97
+
98
+ def test_custom_factory
99
+ custom_factory = RGeo::Cartesian.preferred_factory(buffer_resolution: 8, srid: 3857)
100
+ spatial_factory_store.register(custom_factory, geo_type: "polygon", srid: 3857)
101
+ object = klass.new
102
+ boundary = custom_factory.point(1, 2).buffer(3)
103
+ object.boundary = boundary
104
+ object.save!
105
+ object.reload
106
+ assert_equal boundary.to_s, object.boundary.to_s
107
+ end
108
+
109
+ def test_spatial_factory_attrs_parsing
110
+ factory = RGeo::Cartesian.preferred_factory(srid: 3857)
111
+ spatial_factory_store.register(factory, { srid: 3857,
112
+ sql_type: "geometry",
113
+ geo_type: "polygon",
114
+ has_z: false, has_m: false })
115
+
116
+ # wrong factory for default
117
+ spatial_factory_store.default = RGeo::Geographic.spherical_factory(srid: 4326)
118
+
119
+ object = klass.new
120
+ object.boundary = "POLYGON ((0 0, 0 1, 1 1, 1 0, 0 0))"
121
+ object.save!
122
+ object.reload
123
+ assert_equal(factory, object.boundary.factory)
124
+ end
125
+
126
+ def test_spatial_factory_retrieval
127
+ geo_factory = RGeo::Geographic.spherical_factory(srid: 4326)
128
+ spatial_factory_store.register(geo_factory, geo_type: "point", sql_type: "geography")
129
+
130
+ object = klass.new
131
+ object.latlon = "POINT(-122 47)"
132
+ point = object.latlon
133
+ assert_equal 47, point.latitude
134
+ object.shape = point
135
+
136
+ # test that shape column will not use geographic factory
137
+ object.save!
138
+ object.reload
139
+ refute_equal geo_factory, object.shape.factory
140
+ end
141
+
142
+ def test_point_to_json
143
+ obj = klass.new
144
+ assert_match(/"latlon":null/, obj.to_json)
145
+ obj.latlon = factory.point(1.1, 2.0)
146
+ # NOTE: rgeo opiniated in trimming numbers (e.g 1.0 would be trimmed to 1).
147
+ # We follow this convention here.
148
+ assert_match(/"latlon":"POINT\s\(1.1\s2\)"/, obj.to_json)
149
+ end
150
+
151
+ def test_custom_column
152
+ rec = klass.new
153
+ rec.latlon = "POINT(0 0)"
154
+ rec.save
155
+ refute_nil klass.select("CURRENT_TIMESTAMP as ts").first.ts
156
+ end
157
+
158
+ def test_multi_polygon_column
159
+ rec = klass.new
160
+ wkt = "MULTIPOLYGON (((-73.97210545302842 40.782991711401195, " \
161
+ "-73.97228912063449 40.78274091498208, " \
162
+ "-73.97235226842568 40.78276752827304, " \
163
+ "-73.97216860098405 40.783018324791776, " \
164
+ "-73.97210545302842 40.782991711401195)))"
165
+ rec.m_poly = wkt
166
+ assert rec.save
167
+ rec = klass.find(rec.id) # force reload
168
+ assert RGeo::Feature::MultiPolygon.check_type(rec.m_poly)
169
+ assert_equal wkt, rec.m_poly.to_s
170
+ end
171
+
172
+ private
173
+
174
+ def klass
175
+ Building
176
+ end
177
+
178
+ def reset_memoized_spatial_factories
179
+ # necessary to reset the @spatial_factory variable on spatial
180
+ # OIDs, otherwise the results of early tests will be memoized
181
+ # since the table is not dropped and recreated between test cases.
182
+ klass.lease_connection.send(:reload_type_map)
183
+ klass.reset_column_information
184
+ end
185
+ end
@@ -0,0 +1,115 @@
1
+ require "cases/helper_cockroachdb"
2
+ require "cases/helper"
3
+ require "support/ddl_helper"
4
+ require "support/connection_helper"
5
+ require "support/copy_cat"
6
+
7
+ module CockroachDB
8
+ module ConnectionAdapters
9
+ class PostgreSQLAdapterTest < ActiveRecord::PostgreSQLTestCase
10
+ self.use_transactional_tests = false
11
+ include DdlHelper
12
+ include ConnectionHelper
13
+
14
+ def setup
15
+ @connection = ActiveRecord::Base.lease_connection
16
+ end
17
+
18
+ def teardown
19
+ # use connection without follower_reads and telemetry
20
+ database_config = { "adapter" => "cockroachdb", "database" => "activerecord_unittest" }
21
+ ar_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
22
+ database_config.update(ar_config.configuration_hash)
23
+
24
+ ActiveRecord::Base.establish_connection(database_config)
25
+ end
26
+
27
+ def test_database_exists_returns_false_when_the_database_does_not_exist
28
+ config_base = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary").configuration_hash
29
+ [ config_base.merge(database: "non_extant_database", adapter: "cockroachdb"),
30
+ config_base.merge(database: "non_extant_database", adapter: "postgresql")
31
+ ].each do |config|
32
+ assert_not ActiveRecord::ConnectionAdapters::CockroachDBAdapter.database_exists?(config),
33
+ "expected database #{config[:database]} to not exist"
34
+ end
35
+ end
36
+
37
+ def test_database_exists_returns_true_when_the_database_exists
38
+ db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
39
+ assert ActiveRecord::ConnectionAdapters::CockroachDBAdapter.database_exists?(db_config.configuration_hash),
40
+ "expected database #{db_config.database} to exist"
41
+ end
42
+
43
+ def test_using_telemetry_builtin_connects_properly
44
+ database_config = { "adapter" => "cockroachdb", "database" => "activerecord_unittest" }
45
+ ar_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
46
+ database_config.update(ar_config.configuration_hash)
47
+ database_config[:disable_cockroachdb_telemetry] = false
48
+
49
+ ActiveRecord::Base.establish_connection(database_config)
50
+ conn = ActiveRecord::Base.lease_connection
51
+ conn_config = conn.instance_variable_get("@config")
52
+
53
+ assert_equal(false, conn_config[:disable_cockroachdb_telemetry])
54
+ end
55
+
56
+ def test_using_follower_reads_connects_properly
57
+ database_config = { "use_follower_reads_for_type_introspection": true, "adapter" => "cockroachdb", "database" => "activerecord_unittest" }
58
+ ar_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
59
+ database_config.update(ar_config.configuration_hash)
60
+
61
+ ActiveRecord::Base.establish_connection(database_config)
62
+ conn = ActiveRecord::Base.lease_connection
63
+ conn_config = conn.instance_variable_get("@config")
64
+
65
+ assert conn_config[:use_follower_reads_for_type_introspection]
66
+ end
67
+
68
+ # OVERRIDE: CockroachDB adds parentheses around the WHERE clause's content.
69
+ def test_partial_index_on_column_named_like_keyword
70
+ with_example_table('id serial primary key, number integer, "primary" boolean') do
71
+ @connection.add_index "ex", "id", name: "partial", where: "primary" # "primary" is a keyword
72
+ index = @connection.indexes("ex").find { |idx| idx.name == "partial" }
73
+ assert_equal '("primary")', index.where
74
+ end
75
+ end
76
+
77
+ # OVERRIDE: Different behaviour between PostgreSQL and CockroachDB.
78
+ def test_invalid_index
79
+ with_example_table do
80
+ @connection.exec_query("INSERT INTO ex (number) VALUES (1), (1)")
81
+ error = assert_raises(ActiveRecord::RecordNotUnique) do
82
+ @connection.add_index(:ex, :number, unique: true, algorithm: :concurrently, name: :invalid_index)
83
+ end
84
+ assert_match(/duplicate key value violates unique constraint/, error.message)
85
+ assert_equal @connection.pool, error.connection_pool
86
+
87
+ # In CRDB this tests won't create the index at all.
88
+ assert_not @connection.index_exists?(:ex, :number, name: :invalid_index)
89
+ end
90
+ end
91
+
92
+ # OVERRIDE: the `default_sequence_name` is `nil`, let's `to_s` it
93
+ # for a fair comparison.
94
+ CopyCat.copy_methods(self, ActiveRecord::ConnectionAdapters::PostgreSQLAdapterTest,
95
+ :test_pk_and_sequence_for,
96
+ :test_pk_and_sequence_for_with_non_standard_primary_key
97
+ ) do
98
+ attr_accessor :already_updated
99
+ def on_send(node)
100
+ return super unless node in [:send, _, :default_sequence_name, [:str, "ex"], [:str, "id"|"code"]]
101
+
102
+ raise "The source code must have changed" if already_updated
103
+ already_updated ||= :yes
104
+ insert_after(node.loc.expression, ".to_s")
105
+ end
106
+ end
107
+
108
+ private
109
+
110
+ CopyCat.copy_methods(self, ActiveRecord::ConnectionAdapters::PostgreSQLAdapterTest,
111
+ :with_example_table
112
+ )
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,30 @@
1
+ require "cases/helper_cockroachdb"
2
+
3
+ # Load dependencies from ActiveRecord test suite
4
+ require "support/schema_dumping_helper"
5
+
6
+ module CockroachDB
7
+ class PostgresqlQuotingTest < ActiveRecord::PostgreSQLTestCase
8
+ def setup
9
+ @conn = ActiveRecord::Base.lease_connection
10
+ @raise_int_wider_than_64bit = ActiveRecord.raise_int_wider_than_64bit
11
+ end
12
+
13
+ # Replace the original test since numbers are quoted.
14
+ def test_do_not_raise_when_int_is_not_wider_than_64bit
15
+ value = 9223372036854775807
16
+ assert_equal "'9223372036854775807'", @conn.quote(value)
17
+
18
+ value = -9223372036854775808
19
+ assert_equal "'-9223372036854775808'", @conn.quote(value)
20
+ end
21
+
22
+ # Replace the original test since numbers are quoted.
23
+ def test_do_not_raise_when_raise_int_wider_than_64bit_is_false
24
+ ActiveRecord.raise_int_wider_than_64bit = false
25
+ value = 9223372036854775807 + 1
26
+ assert_equal "'9223372036854775808'", @conn.quote(value)
27
+ ActiveRecord.raise_int_wider_than_64bit = @raise_int_wider_than_64bit
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cases/helper_cockroachdb'
4
+ require 'models/building'
5
+
6
+ class SchemaStatementsTest < ActiveRecord::PostgreSQLTestCase
7
+ def test_no_crdb_internal_in_schema_names
8
+ assert_not_includes Building.lease_connection.schema_names, "crdb_internal"
9
+ end
10
+
11
+ def test_initialize_type_map
12
+ initialized_types = Building.lease_connection.send(:type_map).keys
13
+
14
+ # PostGIS types must be initialized first, so
15
+ # ActiveRecord::ConnectionAdapters::PostgreSQLAdapter#load_additional_types can use them.
16
+ # https://github.com/rails/rails/blob/8d57cb39a88787bb6cfb7e1c481556ef6d8ede7a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L593
17
+ assert_equal initialized_types.first(9), %w[
18
+ geography
19
+ geometry
20
+ geometry_collection
21
+ line_string
22
+ multi_line_string
23
+ multi_point
24
+ multi_polygon
25
+ st_point
26
+ st_polygon
27
+ ]
28
+ end
29
+ end