diff --git a/docker-compose.yml b/docker-compose.yml index 46873b43235..41f6c75900d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '3' services: cockroach_23_1: - image: prismagraphql/cockroachdb-custom:23.1@sha256:c5a97355d56a7692ed34d835dfd8e3663d642219ea90736658a24840ea26862d + image: prismagraphql/cockroachdb-custom:23.1.13 restart: unless-stopped command: | start-single-node --insecure diff --git a/psl/psl-core/src/builtin_connectors/cockroach_datamodel_connector.rs b/psl/psl-core/src/builtin_connectors/cockroach_datamodel_connector.rs index 03b312ba357..61188735d9f 100644 --- a/psl/psl-core/src/builtin_connectors/cockroach_datamodel_connector.rs +++ b/psl/psl-core/src/builtin_connectors/cockroach_datamodel_connector.rs @@ -369,6 +369,8 @@ impl SequenceFunction { let mut this = SequenceFunction::default(); for arg in &args.arguments { + println!("arg.value: {:?}", &arg.value); + match arg.name.as_ref().map(|arg| arg.name.as_str()) { Some("virtual") => this.r#virtual = coerce::boolean(&arg.value, diagnostics), Some("cache") => this.cache = coerce::integer(&arg.value, diagnostics), diff --git a/schema-engine/connectors/sql-schema-connector/src/introspection/introspection_pair/scalar_field.rs b/schema-engine/connectors/sql-schema-connector/src/introspection/introspection_pair/scalar_field.rs index e0536b70f43..f55fdde6625 100644 --- a/schema-engine/connectors/sql-schema-connector/src/introspection/introspection_pair/scalar_field.rs +++ b/schema-engine/connectors/sql-schema-connector/src/introspection/introspection_pair/scalar_field.rs @@ -215,7 +215,7 @@ impl<'a> ScalarFieldPair<'a> { self.previous.is_none() && self.description().is_some() } - fn column_type_family(self) -> &'a sql::ColumnTypeFamily { + pub(crate) fn column_type_family(self) -> &'a sql::ColumnTypeFamily { self.next.column_type_family() } } diff --git a/schema-engine/connectors/sql-schema-connector/src/introspection/rendering/defaults.rs b/schema-engine/connectors/sql-schema-connector/src/introspection/rendering/defaults.rs index ad8ef45e192..10df94edda9 100644 --- a/schema-engine/connectors/sql-schema-connector/src/introspection/rendering/defaults.rs +++ b/schema-engine/connectors/sql-schema-connector/src/introspection/rendering/defaults.rs @@ -1,23 +1,31 @@ //! The `@default` attribute rendering. -use crate::introspection::introspection_pair::{DefaultKind, DefaultValuePair}; +use crate::introspection::introspection_pair::{DefaultKind, DefaultValuePair, ScalarFieldPair}; use datamodel_renderer::{ datamodel as renderer, value::{Constant, Function, Text, Value}, }; /// Render a default value for the given scalar field. -pub(crate) fn render(default: DefaultValuePair<'_>) -> Option> { +pub(crate) fn render<'a>(field: &ScalarFieldPair<'a>) -> Option> { + let default: DefaultValuePair<'a> = field.default(); + let field_family_type = field.column_type_family(); + let mut rendered = match default.kind() { Some(kind) => match kind { DefaultKind::Sequence(sequence) => { let mut fun = Function::new("sequence"); + // 1 is the default value for the "minValue" attribute if sequence.min_value != 1 { fun.push_param(("minValue", Constant::from(sequence.min_value))); } - if sequence.max_value != i64::MAX { + // `i64::MAX` is the default value for the "maxValue" attribute for INT8 sequences; + // `i32::MAX` is the default value for the "maxValue" attribute for INT4 sequences + if (field_family_type.is_bigint() && sequence.max_value != i64::MAX) + || (field_family_type.is_int() && sequence.max_value != i32::MAX as i64) + { fun.push_param(("maxValue", Constant::from(sequence.max_value))); } diff --git a/schema-engine/connectors/sql-schema-connector/src/introspection/rendering/scalar_field.rs b/schema-engine/connectors/sql-schema-connector/src/introspection/rendering/scalar_field.rs index 40ee936d21c..24cbc128783 100644 --- a/schema-engine/connectors/sql-schema-connector/src/introspection/rendering/scalar_field.rs +++ b/schema-engine/connectors/sql-schema-connector/src/introspection/rendering/scalar_field.rs @@ -33,7 +33,7 @@ pub(crate) fn render(field: ScalarFieldPair<'_>) -> renderer::Field<'_> { rendered.documentation(docs); } - if let Some(default) = defaults::render(field.default()) { + if let Some(default) = defaults::render(&field) { rendered.default(default); } diff --git a/schema-engine/connectors/sql-schema-connector/src/sql_schema_calculator/sql_schema_calculator_flavour/postgres.rs b/schema-engine/connectors/sql-schema-connector/src/sql_schema_calculator/sql_schema_calculator_flavour/postgres.rs index 656fe432a97..2e94c2176e5 100644 --- a/schema-engine/connectors/sql-schema-connector/src/sql_schema_calculator/sql_schema_calculator_flavour/postgres.rs +++ b/schema-engine/connectors/sql-schema-connector/src/sql_schema_calculator/sql_schema_calculator_flavour/postgres.rs @@ -123,6 +123,11 @@ impl SqlSchemaCalculatorFlavour for PostgresFlavour { name: format!("prisma_sequence_{}_{}", model.database_name(), field.database_name()), ..Default::default() }; + + // if self.is_cockroachdb() && !field.scalar_field_type().is_bigint() { + // sequence.max_value = i32::MAX.into(); + // } + let sequence_fn = field_default.ast_attribute().arguments.arguments[0] .value .as_function() diff --git a/schema-engine/connectors/sql-schema-connector/src/sql_schema_differ/sql_schema_differ_flavour/postgres.rs b/schema-engine/connectors/sql-schema-connector/src/sql_schema_differ/sql_schema_differ_flavour/postgres.rs index 81db61b7dae..ac025fe89a2 100644 --- a/schema-engine/connectors/sql-schema-connector/src/sql_schema_differ/sql_schema_differ_flavour/postgres.rs +++ b/schema-engine/connectors/sql-schema-connector/src/sql_schema_differ/sql_schema_differ_flavour/postgres.rs @@ -106,6 +106,12 @@ impl SqlSchemaDifferFlavour for PostgresFlavour { .schemas .map(|schema| (schema, schema.describer_schema.downcast_connector_data())); + let sequences = &schemas.previous.1.sequences; + println!("sequences (prev) = {:?}", &sequences); + + let sequences = &schemas.next.1.sequences; + println!("sequences (next) = {:?}", &sequences); + let sequence_pairs = db .all_column_pairs() .map(|cols| { @@ -128,6 +134,10 @@ impl SqlSchemaDifferFlavour for PostgresFlavour { let next = pair.next.1; let mut changes: BitFlags = BitFlags::default(); + // With CockroachDB 23.1, `migrations::cockroachdb::sequence_int4_works` yields: + println!("prev.max_value = {}", &prev.max_value); // 2147483647 + println!("next.max_value = {}", &next.max_value); // 9223372036854775807 + if prev.min_value != next.min_value { changes |= SequenceChange::MinValue; } diff --git a/schema-engine/sql-introspection-tests/src/test_api.rs b/schema-engine/sql-introspection-tests/src/test_api.rs index 524b55e9f2d..bce7d57dba9 100644 --- a/schema-engine/sql-introspection-tests/src/test_api.rs +++ b/schema-engine/sql-introspection-tests/src/test_api.rs @@ -88,14 +88,6 @@ impl TestApi { } else if tags.contains(Tags::CockroachDb) { let (_, q, cs) = args.create_postgres_database().await; - q.raw_cmd( - r#" - SET default_int_size = 4; - "#, - ) - .await - .unwrap(); - let mut me = SqlSchemaConnector::new_cockroach(); let params = ConnectorParams { @@ -146,6 +138,21 @@ impl TestApi { } } + // Call this function when you want the SQL `INT` type to always be mapped to the PSL `Int` type. + // On CockroachDB, for instance, `INT` is an alias to `INT8` (rather than `INT4`), which would + // normally be mapped to `BigInt` in PSL. + // This method is especially useful when testing the same assertions against multiple database providers. + pub async fn normalise_int_type(&self) -> Result<()> { + if self.is_cockroach() { + self.database + .raw_cmd("SET default_int_size = 4") + .await + .expect("Failed to alias INT to INT4 on CockroachDB"); + } + + Ok(()) + } + pub fn connection_string(&self) -> &str { &self.connection_string } diff --git a/schema-engine/sql-introspection-tests/tests/cockroachdb/gin.rs b/schema-engine/sql-introspection-tests/tests/cockroachdb/gin.rs index 148cdb3761b..c1d9e2c9e43 100644 --- a/schema-engine/sql-introspection-tests/tests/cockroachdb/gin.rs +++ b/schema-engine/sql-introspection-tests/tests/cockroachdb/gin.rs @@ -55,8 +55,8 @@ async fn array_ops(api: &mut TestApi) -> TestResult { let expected = expect![[r#" model A { - id BigInt @id @default(autoincrement()) - data Int[] + id BigInt @id @default(autoincrement()) + data BigInt[] @@index([data], type: Gin) } diff --git a/schema-engine/sql-introspection-tests/tests/cockroachdb/mod.rs b/schema-engine/sql-introspection-tests/tests/cockroachdb/mod.rs index 8261648be0b..745fcb131d0 100644 --- a/schema-engine/sql-introspection-tests/tests/cockroachdb/mod.rs +++ b/schema-engine/sql-introspection-tests/tests/cockroachdb/mod.rs @@ -116,7 +116,32 @@ async fn identity_introspects_to_sequence_with_default_settings_v_22_2(api: Test let expected = expect![[r#" model myTable { - id Int @id @default(sequence(maxValue: 2147483647)) + id Int @id @default(sequence(maxValue: 9223372036854775807)) + name String + } + "#]]; + + expected.assert_eq(&result); +} + +#[test_connector(tags(CockroachDb231))] +async fn identity_introspects_to_sequence_with_default_settings_v_23_1(api: TestApi) { + let sql = r#" + CREATE TABLE "myTable" ( + id INT4 GENERATED BY DEFAULT AS IDENTITY, + name STRING NOT NULL, + + PRIMARY KEY (id) + ); + "#; + + api.raw_cmd(sql).await; + + let result = api.introspect_dml().await.unwrap(); + + let expected = expect![[r#" + model myTable { + id Int @id @default(sequence()) name String } "#]]; @@ -245,6 +270,11 @@ async fn scalar_list_defaults_work_on_22_2(api: &mut TestApi) -> TestResult { api.raw_cmd(schema).await; + // Info: + // Column "datetime_defaults" changes in CockroachDb231: + // ``` + // datetime_defaults DateTime[] @default(dbgenerated("'{\"''2022-09-01 08:00:00+00''::TIMESTAMPTZ\",\"''2021-09-01 08:00:00+00''::TIMESTAMPTZ\"}'::TIMESTAMPTZ[]")) @db.Timestamptz + // ``` let expectation = expect![[r#" generator client { provider = "prisma-client-js" @@ -279,6 +309,60 @@ async fn scalar_list_defaults_work_on_22_2(api: &mut TestApi) -> TestResult { Ok(()) } +#[test_connector(tags(CockroachDb231))] +async fn scalar_list_defaults_work_on_23_1(api: &mut TestApi) -> TestResult { + let schema = r#" + CREATE TYPE "color" AS ENUM ('RED', 'GREEN', 'BLUE'); + + CREATE TABLE "defaults" ( + id TEXT PRIMARY KEY, + text_empty TEXT[] NOT NULL DEFAULT '{}', + text TEXT[] NOT NULL DEFAULT '{ ''abc'' }', + text_c_escape TEXT[] NOT NULL DEFAULT E'{ \'abc\', \'def\' }', + colors COLOR[] NOT NULL DEFAULT '{ RED, GREEN }', + int_defaults INT4[] NOT NULL DEFAULT '{ 9, 12999, -4, 0, 1249849 }', + float_defaults DOUBLE PRECISION[] NOT NULL DEFAULT '{ 0.0, 9.12, 3.14, 0.1242, 124949.124949 }', + bool_defaults BOOLEAN[] NOT NULL DEFAULT '{ true, true, true, false }', + datetime_defaults TIMESTAMPTZ[] NOT NULL DEFAULT '{ "2022-09-01T08:00Z","2021-09-01T08:00Z"}' + ); + "#; + + api.raw_cmd(schema).await; + + let expectation = expect![[r#" + generator client { + provider = "prisma-client-js" + } + + datasource db { + provider = "cockroachdb" + url = "env(TEST_DATABASE_URL)" + } + + model defaults { + id String @id + text_empty String[] @default([]) + text String[] @default(["abc"]) + text_c_escape String[] @default(["abc", "def"]) + colors color[] @default([RED, GREEN]) + int_defaults Int[] @default([9, 12999, -4, 0, 1249849]) + float_defaults Float[] @default([0, 9.12, 3.14, 0.1242, 124949.124949]) + bool_defaults Boolean[] @default([true, true, true, false]) + datetime_defaults DateTime[] @default(dbgenerated("'{\"''2022-09-01 08:00:00+00''::TIMESTAMPTZ\",\"''2021-09-01 08:00:00+00''::TIMESTAMPTZ\"}'::TIMESTAMPTZ[]")) @db.Timestamptz + } + + enum color { + RED + GREEN + BLUE + } + "#]]; + + api.expect_datamodel(&expectation).await; + + Ok(()) +} + #[test_connector(tags(CockroachDb))] async fn string_col_with_length(api: &mut TestApi) -> TestResult { let schema = r#" @@ -442,7 +526,7 @@ async fn commenting_stopgap(api: &mut TestApi) -> TestResult { /// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments model a { - id Int @id + id BigInt @id val String? @db.String(20) } "#]]; @@ -461,3 +545,125 @@ async fn commenting_stopgap(api: &mut TestApi) -> TestResult { Ok(()) } + +#[test_connector(tags(CockroachDb231))] +async fn sequences_works_on_23_1(api: &mut TestApi) -> TestResult { + let schema = indoc! {r#" + -- CreateTable + CREATE TABLE "TestModelSeqInt4" ( + "id" INT4 NOT NULL GENERATED BY DEFAULT AS IDENTITY, + + CONSTRAINT "TestModelSeqInt4_pkey" PRIMARY KEY ("id") + ); + + -- CreateTable + CREATE TABLE "TestModelSeqInt8" ( + "id" INT8 NOT NULL GENERATED BY DEFAULT AS IDENTITY, + + CONSTRAINT "TestModelSeqInt8_pkey" PRIMARY KEY ("id") + ); + "#}; + + api.raw_cmd(schema).await; + + let expectation = expect![[r#" + generator client { + provider = "prisma-client-js" + } + + datasource db { + provider = "cockroachdb" + url = "env(TEST_DATABASE_URL)" + } + + model TestModelSeqInt4 { + id Int @id @default(sequence()) + } + + model TestModelSeqInt8 { + id BigInt @id @default(sequence()) + } + "#]]; + + api.expect_datamodel(&expectation).await; + + let expectation = expect![]; + + api.expect_warnings(&expectation).await; + + Ok(()) +} + +#[test_connector(tags(CockroachDb))] +async fn sequences_works_on_23_1_int8(api: &mut TestApi) -> TestResult { + let schema = indoc! {r#" + -- CreateTable + CREATE TABLE "TestModelSeqInt8" ( + "id" INT8 NOT NULL GENERATED BY DEFAULT AS IDENTITY, + + CONSTRAINT "TestModelSeqInt8_pkey" PRIMARY KEY ("id") + ); + "#}; + + api.raw_cmd(schema).await; + + let expectation = expect![[r#" + generator client { + provider = "prisma-client-js" + } + + datasource db { + provider = "cockroachdb" + url = "env(TEST_DATABASE_URL)" + } + + model TestModelSeqInt8 { + id BigInt @id @default(sequence()) + } + "#]]; + + api.expect_datamodel(&expectation).await; + + let expectation = expect![]; + + api.expect_warnings(&expectation).await; + + Ok(()) +} + +#[test_connector(tags(CockroachDb231))] +async fn sequences_works_on_23_1_int4(api: &mut TestApi) -> TestResult { + let schema = indoc! {r#" + -- CreateTable + CREATE TABLE "TestModelSeqInt4" ( + "id" INT4 NOT NULL GENERATED BY DEFAULT AS IDENTITY, + + CONSTRAINT "TestModelSeqInt4_pkey" PRIMARY KEY ("id") + ); + "#}; + + api.raw_cmd(schema).await; + + let expectation = expect![[r#" + generator client { + provider = "prisma-client-js" + } + + datasource db { + provider = "cockroachdb" + url = "env(TEST_DATABASE_URL)" + } + + model TestModelSeqInt4 { + id Int @id @default(sequence()) + } + "#]]; + + api.expect_datamodel(&expectation).await; + + let expectation = expect![]; + + api.expect_warnings(&expectation).await; + + Ok(()) +} diff --git a/schema-engine/sql-introspection-tests/tests/commenting_out/cockroachdb.rs b/schema-engine/sql-introspection-tests/tests/commenting_out/cockroachdb.rs index 888a6037a41..1ccb5dc8d3e 100644 --- a/schema-engine/sql-introspection-tests/tests/commenting_out/cockroachdb.rs +++ b/schema-engine/sql-introspection-tests/tests/commenting_out/cockroachdb.rs @@ -20,9 +20,9 @@ async fn a_table_without_uniques_should_ignore(api: &mut TestApi) -> TestResult let expected = expect![[r#" /// The underlying table does not contain a valid unique identifier and can therefore currently not be handled by Prisma Client. model Post { - id Int - user_id Int - User User @relation(fields: [user_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + id BigInt + user_id BigInt + User User @relation(fields: [user_id], references: [id], onDelete: NoAction, onUpdate: NoAction) @@index([user_id]) @@ignore @@ -58,16 +58,16 @@ async fn ignore_on_back_relation_field_if_pointing_to_ignored_model(api: &mut Te let expected = expect![[r#" /// The underlying table does not contain a valid unique identifier and can therefore currently not be handled by Prisma Client. model Post { - id Int - user_ip Int - User User @relation(fields: [user_ip], references: [ip], onDelete: NoAction, onUpdate: NoAction) + id BigInt + user_ip BigInt + User User @relation(fields: [user_ip], references: [ip], onDelete: NoAction, onUpdate: NoAction) @@ignore } model User { id BigInt @id @default(autoincrement()) - ip Int @unique + ip BigInt @unique Post Post[] @ignore } "#]]; diff --git a/schema-engine/sql-introspection-tests/tests/commenting_out/mod.rs b/schema-engine/sql-introspection-tests/tests/commenting_out/mod.rs index 06aa82a27bb..3f8722b4efa 100644 --- a/schema-engine/sql-introspection-tests/tests/commenting_out/mod.rs +++ b/schema-engine/sql-introspection-tests/tests/commenting_out/mod.rs @@ -47,6 +47,8 @@ async fn a_table_without_uniques_should_ignore(api: &mut TestApi) -> TestResult #[test_connector(exclude(Sqlite, Mysql))] async fn a_table_without_required_uniques(api: &mut TestApi) -> TestResult { + api.normalise_int_type().await?; + api.barrel() .execute(|migration| { migration.create_table("Post", |t| { diff --git a/schema-engine/sql-introspection-tests/tests/lists/mod.rs b/schema-engine/sql-introspection-tests/tests/lists/mod.rs index 6d4ad7c7b2f..3fed117f9b0 100644 --- a/schema-engine/sql-introspection-tests/tests/lists/mod.rs +++ b/schema-engine/sql-introspection-tests/tests/lists/mod.rs @@ -5,6 +5,8 @@ use test_macros::test_connector; #[test_connector(capabilities(ScalarLists))] async fn scalar_list_types(api: &mut TestApi) -> TestResult { + api.normalise_int_type().await?; + api.barrel() .execute(|migration| { migration.create_table("Post", |t| { diff --git a/schema-engine/sql-introspection-tests/tests/multi_schema/cockroach.rs b/schema-engine/sql-introspection-tests/tests/multi_schema/cockroach.rs index 252a1f9fad4..ffb36cb18fb 100644 --- a/schema-engine/sql-introspection-tests/tests/multi_schema/cockroach.rs +++ b/schema-engine/sql-introspection-tests/tests/multi_schema/cockroach.rs @@ -320,7 +320,7 @@ async fn same_table_name_with_relation_in_two_schemas(api: &mut TestApi) -> Test model second_schema_tbl { id BigInt @id @default(autoincrement()) - fst Int? + fst BigInt? tbl first_tbl? @relation(fields: [fst], references: [id], onDelete: NoAction, onUpdate: NoAction) @@map("tbl") diff --git a/schema-engine/sql-introspection-tests/tests/native_types/postgres.rs b/schema-engine/sql-introspection-tests/tests/native_types/postgres.rs index f95c6fcbc89..0dcd4342e55 100644 --- a/schema-engine/sql-introspection-tests/tests/native_types/postgres.rs +++ b/schema-engine/sql-introspection-tests/tests/native_types/postgres.rs @@ -159,6 +159,8 @@ async fn native_type_array_columns_feature_on(api: &mut TestApi) -> TestResult { async fn cdb_char_is_a_char(api: &mut TestApi) -> TestResult { // https://github.com/prisma/prisma/issues/12281 + api.normalise_int_type().await?; + api.barrel() .execute(move |migration| { migration.create_table("Blog", move |t| { diff --git a/schema-engine/sql-introspection-tests/tests/re_introspection/relation_mode/postgres.rs b/schema-engine/sql-introspection-tests/tests/re_introspection/relation_mode/postgres.rs index 7fd2bf185ed..36cc515b07b 100644 --- a/schema-engine/sql-introspection-tests/tests/re_introspection/relation_mode/postgres.rs +++ b/schema-engine/sql-introspection-tests/tests/re_introspection/relation_mode/postgres.rs @@ -4,6 +4,8 @@ use sql_introspection_tests::test_api::*; // referentialIntegrity="prisma" is renamed as relationMode="prisma", and @relations are preserved. #[test_connector(tags(Postgres))] async fn referential_integrity_prisma(api: &mut TestApi) -> TestResult { + api.normalise_int_type().await?; + let init = indoc! {r#" CREATE TABLE "Foo" ( "id" INTEGER NOT NULL, @@ -78,6 +80,8 @@ async fn referential_integrity_prisma(api: &mut TestApi) -> TestResult { // referentialIntegrity="foreignKeys" is renamed as relationMode="foreignKeys", and @relations are preserved but moved to the bottom. #[test_connector(tags(Postgres))] async fn referential_integrity_foreign_keys(api: &mut TestApi) -> TestResult { + api.normalise_int_type().await?; + let init = indoc! {r#" CREATE TABLE "Foo" ( "id" INTEGER NOT NULL, @@ -154,6 +158,8 @@ async fn referential_integrity_foreign_keys(api: &mut TestApi) -> TestResult { // relationMode="prisma" preserves the relation policy ("prisma") as well as @relations. #[test_connector(tags(Postgres))] async fn relation_mode_prisma(api: &mut TestApi) -> TestResult { + api.normalise_int_type().await?; + let init = indoc! {r#" CREATE TABLE "Foo" ( "id" INTEGER NOT NULL, @@ -228,6 +234,8 @@ async fn relation_mode_prisma(api: &mut TestApi) -> TestResult { // relationMode="foreignKeys" preserves the relation policy ("foreignKeys") as well as @relations, which are moved to the bottom. #[test_connector(tags(Postgres))] async fn relation_mode_foreign_keys(api: &mut TestApi) -> TestResult { + api.normalise_int_type().await?; + let init = indoc! {r#" CREATE TABLE "Foo" ( "id" INTEGER NOT NULL, @@ -309,6 +317,8 @@ mod at_at_map { // referentialIntegrity="prisma" is renamed as relationMode="prisma", and @relations are preserved. #[test_connector(tags(Postgres))] async fn referential_integrity_prisma_at_map_map(api: &mut TestApi) -> TestResult { + api.normalise_int_type().await?; + let init = indoc! {r#" CREATE TABLE "foo_table" ( "id" INTEGER NOT NULL, @@ -391,6 +401,8 @@ mod at_at_map { // referentialIntegrity="foreignKeys" is renamed as relationMode="foreignKeys", and @relations are preserved. #[test_connector(tags(Postgres))] async fn referential_integrity_foreign_keys_at_map_map(api: &mut TestApi) -> TestResult { + api.normalise_int_type().await?; + let init = indoc! {r#" CREATE TABLE "foo_table" ( "id" INTEGER NOT NULL, @@ -475,6 +487,8 @@ mod at_at_map { // relationMode="prisma" preserves the relation policy ("prisma") as well as @relations. #[test_connector(tags(Postgres))] async fn relation_mode_prisma_at_map_map(api: &mut TestApi) -> TestResult { + api.normalise_int_type().await?; + let init = indoc! {r#" CREATE TABLE "foo_table" ( "id" INTEGER NOT NULL, @@ -557,6 +571,8 @@ mod at_at_map { // relationMode="foreignKeys" preserves the relation policy ("foreignKeys") as well as @relations., which are moved to the bottom. #[test_connector(tags(Postgres))] async fn relation_mode_foreign_keys_at_map_map(api: &mut TestApi) -> TestResult { + api.normalise_int_type().await?; + let init = indoc! {r#" CREATE TABLE "foo_table" ( "id" INTEGER NOT NULL, diff --git a/schema-engine/sql-introspection-tests/tests/referential_actions/cockroachdb.rs b/schema-engine/sql-introspection-tests/tests/referential_actions/cockroachdb.rs index c1b72e48be5..3552d1d0f51 100644 --- a/schema-engine/sql-introspection-tests/tests/referential_actions/cockroachdb.rs +++ b/schema-engine/sql-introspection-tests/tests/referential_actions/cockroachdb.rs @@ -27,7 +27,7 @@ async fn default_referential_actions_with_restrict(api: &mut TestApi) -> TestRes model b { id BigInt @id @default(autoincrement()) - a_id Int + a_id BigInt a a @relation(fields: [a_id], references: [id], map: "asdf") } "#]]; @@ -64,7 +64,7 @@ async fn referential_actions(api: &mut TestApi) -> TestResult { model b { id BigInt @id @default(autoincrement()) - a_id Int + a_id BigInt a a @relation(fields: [a_id], references: [id], onDelete: Cascade, onUpdate: NoAction, map: "asdf") } "#]]; diff --git a/schema-engine/sql-introspection-tests/tests/relations/cockroachdb.rs b/schema-engine/sql-introspection-tests/tests/relations/cockroachdb.rs index a84cf7f1800..5fd1e7b6dc5 100644 --- a/schema-engine/sql-introspection-tests/tests/relations/cockroachdb.rs +++ b/schema-engine/sql-introspection-tests/tests/relations/cockroachdb.rs @@ -63,9 +63,9 @@ async fn default_values_on_relations(api: &mut TestApi) -> TestResult { let expected = expect![[r#" model Post { - id BigInt @id @default(autoincrement()) - user_id Int? @default(0) - User User? @relation(fields: [user_id], references: [id], onDelete: NoAction, onUpdate: NoAction) + id BigInt @id @default(autoincrement()) + user_id BigInt? @default(0) + User User? @relation(fields: [user_id], references: [id], onDelete: NoAction, onUpdate: NoAction) } model User { @@ -103,13 +103,13 @@ async fn a_self_relation(api: &mut TestApi) -> TestResult { let expected = expect![[r#" model User { - id BigInt @id @default(autoincrement()) - recruited_by Int? - direct_report Int? - User_User_direct_reportToUser User? @relation("User_direct_reportToUser", fields: [direct_report], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "direct_report_fkey") - other_User_User_direct_reportToUser User[] @relation("User_direct_reportToUser") - User_User_recruited_byToUser User? @relation("User_recruited_byToUser", fields: [recruited_by], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "recruited_by_fkey") - other_User_User_recruited_byToUser User[] @relation("User_recruited_byToUser") + id BigInt @id @default(autoincrement()) + recruited_by BigInt? + direct_report BigInt? + User_User_direct_reportToUser User? @relation("User_direct_reportToUser", fields: [direct_report], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "direct_report_fkey") + other_User_User_direct_reportToUser User[] @relation("User_direct_reportToUser") + User_User_recruited_byToUser User? @relation("User_recruited_byToUser", fields: [recruited_by], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "recruited_by_fkey") + other_User_User_recruited_byToUser User[] @relation("User_recruited_byToUser") } "#]]; @@ -149,8 +149,8 @@ async fn a_many_to_many_relation_with_an_id(api: &mut TestApi) -> TestResult { model PostsToUsers { id BigInt @id @default(autoincrement()) - user_id Int - post_id Int + user_id BigInt + post_id BigInt Post Post @relation(fields: [post_id], references: [id], onDelete: NoAction, onUpdate: NoAction) User User @relation(fields: [user_id], references: [id], onDelete: NoAction, onUpdate: NoAction) } diff --git a/schema-engine/sql-introspection-tests/tests/relations/mod.rs b/schema-engine/sql-introspection-tests/tests/relations/mod.rs index 023ee6f83fe..a853c887de1 100644 --- a/schema-engine/sql-introspection-tests/tests/relations/mod.rs +++ b/schema-engine/sql-introspection-tests/tests/relations/mod.rs @@ -538,6 +538,8 @@ async fn prisma_1_0_relations(api: &mut TestApi) -> TestResult { #[test_connector(exclude(Mysql, Sqlite, Mssql))] async fn relations_should_avoid_name_clashes(api: &mut TestApi) -> TestResult { + api.normalise_int_type().await?; + api.barrel() .execute(|migration| { migration.create_table("y", |t| { diff --git a/schema-engine/sql-introspection-tests/tests/relations_with_compound_fk/cockroachdb.rs b/schema-engine/sql-introspection-tests/tests/relations_with_compound_fk/cockroachdb.rs index 97593281093..d400fadaf7d 100644 --- a/schema-engine/sql-introspection-tests/tests/relations_with_compound_fk/cockroachdb.rs +++ b/schema-engine/sql-introspection-tests/tests/relations_with_compound_fk/cockroachdb.rs @@ -58,8 +58,8 @@ async fn compound_foreign_keys_with_defaults_v_22_2(api: &mut TestApi) -> TestRe let expected = expect![[r#" model Person { - id BigInt @id @default(sequence(maxValue: 2147483647)) - age Int + id BigInt @id @default(sequence()) + age BigInt partner_id Int @default(0) partner_age Int @default(0) Person Person @relation("PersonToPerson", fields: [partner_id, partner_age], references: [id, age], onDelete: NoAction, onUpdate: NoAction) diff --git a/schema-engine/sql-introspection-tests/tests/remapping_database_names/mod.rs b/schema-engine/sql-introspection-tests/tests/remapping_database_names/mod.rs index 36a39e5d965..8eac2e76c90 100644 --- a/schema-engine/sql-introspection-tests/tests/remapping_database_names/mod.rs +++ b/schema-engine/sql-introspection-tests/tests/remapping_database_names/mod.rs @@ -360,6 +360,8 @@ async fn remapping_enum_default_values(api: &mut TestApi) -> TestResult { #[test_connector] async fn remapping_compound_primary_keys(api: &mut TestApi) -> TestResult { + api.normalise_int_type().await?; + api.barrel() .execute(|migration| { migration.create_table("User", |t| { @@ -420,6 +422,8 @@ async fn not_automatically_remapping_invalid_compound_unique_key_names(api: &mut #[test_connector] async fn not_automatically_remapping_invalid_compound_primary_key_names(api: &mut TestApi) -> TestResult { + api.normalise_int_type().await?; + api.barrel() .execute(|migration| { migration.create_table("User", |t| { diff --git a/schema-engine/sql-introspection-tests/tests/simple/cockroach/foreign_keys_duplicates_should_be_ignored.sql b/schema-engine/sql-introspection-tests/tests/simple/cockroach/foreign_keys_duplicates_should_be_ignored_22_2_and_down.sql similarity index 96% rename from schema-engine/sql-introspection-tests/tests/simple/cockroach/foreign_keys_duplicates_should_be_ignored.sql rename to schema-engine/sql-introspection-tests/tests/simple/cockroach/foreign_keys_duplicates_should_be_ignored_22_2_and_down.sql index f84da32db05..d6de77c4d5c 100644 --- a/schema-engine/sql-introspection-tests/tests/simple/cockroach/foreign_keys_duplicates_should_be_ignored.sql +++ b/schema-engine/sql-introspection-tests/tests/simple/cockroach/foreign_keys_duplicates_should_be_ignored_22_2_and_down.sql @@ -1,4 +1,5 @@ -- tags=cockroachdb +-- exclude=CockroachDb231 CREATE TABLE "User" ( id INT4 GENERATED BY DEFAULT AS IDENTITY, @@ -17,6 +18,7 @@ ALTER TABLE "Post" REFERENCES "User"(id); + /* generator js { provider = "prisma-client-js" diff --git a/schema-engine/sql-introspection-tests/tests/simple/cockroach/foreign_keys_duplicates_should_be_ignored_23_1_and_up.sql b/schema-engine/sql-introspection-tests/tests/simple/cockroach/foreign_keys_duplicates_should_be_ignored_23_1_and_up.sql new file mode 100644 index 00000000000..fb3d922549d --- /dev/null +++ b/schema-engine/sql-introspection-tests/tests/simple/cockroach/foreign_keys_duplicates_should_be_ignored_23_1_and_up.sql @@ -0,0 +1,41 @@ +-- tags=CockroachDb231 + +CREATE TABLE "User" ( + id INT4 GENERATED BY DEFAULT AS IDENTITY, + CONSTRAINT "User_pkey" PRIMARY KEY (id) +); + +CREATE TABLE "Post" ( + id INT4 GENERATED BY DEFAULT AS IDENTITY, + user_id INT4 REFERENCES "User"(id), + CONSTRAINT "Post_pkey" PRIMARY KEY (id) +); + +ALTER TABLE "Post" + ADD CONSTRAINT "second_fk" + FOREIGN KEY (user_id) + REFERENCES "User"(id); + + + +/* +generator js { + provider = "prisma-client-js" +} + +datasource db { + provider = "cockroachdb" + url = env("DATABASE_URL") +} + +model Post { + id Int @id @default(sequence(maxValue: 2147483647)) + user_id Int? + User User? @relation(fields: [user_id], references: [id], onDelete: NoAction, onUpdate: NoAction) +} + +model User { + id Int @id @default(sequence(maxValue: 2147483647)) + Post Post[] +} +*/ diff --git a/schema-engine/sql-introspection-tests/tests/tables/cockroachdb.rs b/schema-engine/sql-introspection-tests/tests/tables/cockroachdb.rs index 0826b7b182f..55cf3cd33ca 100644 --- a/schema-engine/sql-introspection-tests/tests/tables/cockroachdb.rs +++ b/schema-engine/sql-introspection-tests/tests/tables/cockroachdb.rs @@ -149,6 +149,8 @@ async fn default_values(api: &mut TestApi) -> TestResult { #[test_connector(tags(CockroachDb))] async fn a_simple_table_with_gql_types(api: &mut TestApi) -> TestResult { + api.normalise_int_type().await?; + api.barrel() .execute(|migration| { migration.create_table("Blog", move |t| { @@ -232,7 +234,7 @@ async fn a_table_with_non_id_autoincrement_cockroach(api: &mut TestApi) -> TestR let dm = indoc! {r#" model Test { - id Int @id + id BigInt @id authorId BigInt @default(autoincrement()) @unique } "#}; @@ -259,11 +261,11 @@ async fn introspecting_json_defaults_on_cockroach(api: &mut TestApi) -> TestResu let expectation = expect![[r#" model A { - id Int @id - json Json? @default("[]") - jsonb Json? @default("{}") - jsonb_string Json? @default("\"ab'c\"") - jsonb_object Json? @default("{\"a\": [\"b'\"], \"c\": true, \"d\": null}") + id BigInt @id + json Json? @default("[]") + jsonb Json? @default("{}") + jsonb_string Json? @default("\"ab'c\"") + jsonb_object Json? @default("{\"a\": [\"b'\"], \"c\": true, \"d\": null}") } "#]]; @@ -300,7 +302,7 @@ $$ } model stringstest { - id Int @id + id BigInt @id needs_escaping String @default("\nabc def\nbackspaces: \\abcd\\\n\t(tab character)\nand \"quotes\" and a vertical tabulation here ->x16<-\n\n") } "#]]; @@ -334,7 +336,7 @@ async fn datetime_default_expressions_are_not_truncated(api: &mut TestApi) -> Te } model Foo { - id Int @id + id BigInt @id trial_expires DateTime @default(dbgenerated("now() + '14 days'::INTERVAL")) @db.Timestamptz(6) } "#]]; @@ -473,7 +475,7 @@ async fn northwind(api: TestApi) { units_in_stock Int? @db.Int2 units_on_order Int? @db.Int2 reorder_level Int? @db.Int2 - discontinued Int + discontinued BigInt order_details order_details[] categories categories? @relation(fields: [category_id], references: [category_id], onDelete: NoAction, onUpdate: NoAction, map: "fk_products_categories") suppliers suppliers? @relation(fields: [supplier_id], references: [supplier_id], onDelete: NoAction, onUpdate: NoAction, map: "fk_products_suppliers") diff --git a/schema-engine/sql-introspection-tests/tests/tables/mod.rs b/schema-engine/sql-introspection-tests/tests/tables/mod.rs index 3fc69cdf9c5..5816deaee07 100644 --- a/schema-engine/sql-introspection-tests/tests/tables/mod.rs +++ b/schema-engine/sql-introspection-tests/tests/tables/mod.rs @@ -146,6 +146,8 @@ async fn should_ignore_prisma_helper_tables(api: &mut TestApi) -> TestResult { #[test_connector] async fn a_table_with_compound_primary_keys(api: &mut TestApi) -> TestResult { + api.normalise_int_type().await?; + api.barrel() .execute(|migration| { migration.create_table("Blog", |t| { diff --git a/schema-engine/sql-introspection-tests/tests/tables/postgres.rs b/schema-engine/sql-introspection-tests/tests/tables/postgres.rs index 3bd127bf83a..b2ae60ea53a 100644 --- a/schema-engine/sql-introspection-tests/tests/tables/postgres.rs +++ b/schema-engine/sql-introspection-tests/tests/tables/postgres.rs @@ -41,6 +41,8 @@ $$ #[test_connector(tags(Postgres))] async fn a_table_with_descending_unique(api: &mut TestApi) -> TestResult { + api.normalise_int_type().await?; + let setup = r#" CREATE TABLE "A" ( id INTEGER NOT NULL, @@ -67,6 +69,8 @@ async fn a_table_with_descending_unique(api: &mut TestApi) -> TestResult { #[test_connector(tags(Postgres))] async fn a_table_with_descending_compound_unique(api: &mut TestApi) -> TestResult { + api.normalise_int_type().await?; + let setup = indoc! {r#" CREATE TABLE "A" ( id INTEGER NOT NULL, @@ -97,6 +101,8 @@ async fn a_table_with_descending_compound_unique(api: &mut TestApi) -> TestResul #[test_connector(tags(Postgres))] async fn a_table_with_descending_index(api: &mut TestApi) -> TestResult { + api.normalise_int_type().await?; + let setup = indoc! {r#" CREATE TABLE "A" ( id INTEGER NOT NULL, @@ -155,6 +161,8 @@ async fn a_table_with_a_hash_index(api: &mut TestApi) -> TestResult { #[test_connector(tags(Postgres))] async fn ignoring_of_partial_indices(api: &mut TestApi) -> TestResult { + api.normalise_int_type().await?; + let setup = indoc! {r#" CREATE TABLE "A" ( id INTEGER NOT NULL, @@ -181,6 +189,8 @@ async fn ignoring_of_partial_indices(api: &mut TestApi) -> TestResult { #[test_connector(tags(Postgres))] async fn introspecting_now_functions(api: &mut TestApi) -> TestResult { + api.normalise_int_type().await?; + let setup = indoc! {r#" CREATE TABLE "A" ( id INTEGER NOT NULL Primary Key, diff --git a/schema-engine/sql-migration-tests/tests/migrations/cockroachdb.rs b/schema-engine/sql-migration-tests/tests/migrations/cockroachdb.rs index 5612e04cb68..c162d2962ad 100644 --- a/schema-engine/sql-migration-tests/tests/migrations/cockroachdb.rs +++ b/schema-engine/sql-migration-tests/tests/migrations/cockroachdb.rs @@ -1231,42 +1231,93 @@ fn json_defaults_with_escaped_quotes_work(api: TestApi) { } #[test_connector(tags(CockroachDb))] -fn sequence_with_multiple_models_works(api: TestApi) { +fn sequence_int8_works(api: TestApi) { let schema = r#" datasource db { - provider = "cockroachdb" - url = env("DATABASE_URL") + provider = "cockroachdb" + url = "env(TEST_DATABASE_URL)" } - - model TestModel { - id BigInt @id @default(autoincrement()) + + model TestModelSeqInt8 { + id BigInt @id @default(sequence()) } + "#; - model TestModelSeq { - name String + let sql = expect![[r#" + -- CreateTable + CREATE TABLE "TestModelSeqInt8" ( + "id" INT8 NOT NULL GENERATED BY DEFAULT AS IDENTITY, + + CONSTRAINT "TestModelSeqInt8_pkey" PRIMARY KEY ("id") + ); + "#]]; + + api.expect_sql_for_schema(schema, &sql); + api.schema_push(schema).send().assert_green(); + api.schema_push(schema).send().assert_green().assert_no_steps(); +} + +#[test_connector(tags(CockroachDb))] +fn sequence_int4_works(api: TestApi) { + let schema = r#" + datasource db { + provider = "cockroachdb" + url = "env(TEST_DATABASE_URL)" + } + + model TestModelSeqInt4 { id Int @id @default(sequence()) } "#; let sql = expect![[r#" -- CreateTable - CREATE TABLE "TestModel" ( - "id" INT8 NOT NULL DEFAULT unique_rowid(), + CREATE TABLE "TestModelSeqInt4" ( + "id" INT4 NOT NULL GENERATED BY DEFAULT AS IDENTITY, - CONSTRAINT "TestModel_pkey" PRIMARY KEY ("id") + CONSTRAINT "TestModelSeqInt4_pkey" PRIMARY KEY ("id") ); + "#]]; + + api.expect_sql_for_schema(schema, &sql); + api.schema_push(schema).send().assert_green(); + api.schema_push(schema).send().assert_green().assert_no_steps(); +} + +#[test_connector(tags(CockroachDb))] +fn sequence_with_multiple_models_works(api: TestApi) { + let schema = r#" + datasource db { + provider = "cockroachdb" + url = "env(TEST_DATABASE_URL)" + } + + model TestModelSeqInt4 { + id Int @id @default(sequence(maxValue: 9223372036854775807)) + } + + model TestModelSeqInt8 { + id BigInt @id @default(sequence()) + } + "#; + let sql = expect![[r#" -- CreateTable - CREATE TABLE "TestModelSeq" ( - "name" STRING NOT NULL, + CREATE TABLE "TestModelSeqInt4" ( "id" INT4 NOT NULL GENERATED BY DEFAULT AS IDENTITY, - CONSTRAINT "TestModelSeq_pkey" PRIMARY KEY ("id") + CONSTRAINT "TestModelSeqInt4_pkey" PRIMARY KEY ("id") + ); + + -- CreateTable + CREATE TABLE "TestModelSeqInt8" ( + "id" INT8 NOT NULL GENERATED BY DEFAULT AS IDENTITY, + + CONSTRAINT "TestModelSeqInt8_pkey" PRIMARY KEY ("id") ); "#]]; api.expect_sql_for_schema(schema, &sql); - api.schema_push(schema).send().assert_green(); api.schema_push(schema).send().assert_green().assert_no_steps(); } diff --git a/schema-engine/sql-schema-describer/src/postgres.rs b/schema-engine/sql-schema-describer/src/postgres.rs index 211cf8da489..36d72ff4b40 100644 --- a/schema-engine/sql-schema-describer/src/postgres.rs +++ b/schema-engine/sql-schema-describer/src/postgres.rs @@ -177,6 +177,13 @@ impl PostgresSchemaExt { } pub fn get_sequence(&self, name: &str) -> Option<(usize, &Sequence)> { + // Debug `migrations::cockroachdb::sequence_int4_works`: + // We're receiving requests for sequences: + // - "TestModelSeqInt4_id_seq" (min_value: 1, max_value: 2147483647) + // - "prisma_sequence_TestModelSeqInt4_id" (min_value: 1, max_value: 9223372036854775807) + println!("getting sequence \"{}\"", &name); + println!("sequences:\n{:?}", &self.sequences); + self.sequences .binary_search_by_key(&name, |s| &s.name) .map(|idx| (idx, &self.sequences[idx])) diff --git a/schema-engine/sql-schema-describer/tests/describers/postgres_describer_tests/cockroach_describer_tests.rs b/schema-engine/sql-schema-describer/tests/describers/postgres_describer_tests/cockroach_describer_tests.rs index ccbac9fdc7d..072590a008f 100644 --- a/schema-engine/sql-schema-describer/tests/describers/postgres_describer_tests/cockroach_describer_tests.rs +++ b/schema-engine/sql-schema-describer/tests/describers/postgres_describer_tests/cockroach_describer_tests.rs @@ -499,7 +499,7 @@ fn cockroachdb_22_1_sequences_must_work(api: TestApi) { expected_ext.assert_debug_eq(&ext); } -#[test_connector(tags(CockroachDb222))] +#[test_connector(tags(CockroachDb))] fn cockroachdb_22_2_sequences_must_work(api: TestApi) { // https://www.cockroachlabs.com/docs/v21.2/create-sequence.html let sql = r#"