From f3784ac5d8844eea62dbeba74ee4dd1145838989 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Thu, 23 Nov 2023 01:32:46 +0100 Subject: [PATCH 001/103] feat: geospatial types support --- .github/workflows/test-query-engine.yml | 16 + .github/workflows/test-schema-engine.yml | 2 + .test_database_urls/postgis_15 | 1 + Cargo.lock | 112 ++- Makefile | 6 + docker-compose.yml | 13 + libs/prisma-value/src/lib.rs | 4 + libs/test-setup/src/postgres.rs | 9 +- libs/test-setup/src/sqlite.rs | 18 + libs/test-setup/src/tags.rs | 2 + libs/test-setup/src/test_api_args.rs | 4 +- prisma-fmt/tests/native_types.rs | 2 +- .../src/cockroach_datamodel_connector.rs | 41 +- .../native_types.rs | 4 + psl/builtin-connectors/src/geometry.rs | 355 +++++++++ psl/builtin-connectors/src/lib.rs | 3 + psl/builtin-connectors/src/mongodb.rs | 1 + .../src/mongodb/mongodb_types.rs | 3 +- .../src/mssql_datamodel_connector.rs | 10 + .../mssql_datamodel_connector/native_types.rs | 2 + .../src/mysql_datamodel_connector.rs | 37 + .../mysql_datamodel_connector/native_types.rs | 8 + .../mysql_datamodel_connector/validations.rs | 8 + .../src/postgres_datamodel_connector.rs | 39 +- .../native_types.rs | 4 + .../src/sqlite_datamodel_connector.rs | 98 ++- .../native_types.rs | 7 + psl/parser-database/src/attributes/default.rs | 2 + psl/parser-database/src/types.rs | 19 +- psl/psl-core/src/datamodel_connector.rs | 12 + .../src/datamodel_connector/capabilities.rs | 6 + .../datamodel_connector/empty_connector.rs | 1 + .../validations/default_value.rs | 2 + .../validation_pipeline/validations/fields.rs | 32 + psl/psl/tests/base/base_types.rs | 5 + .../tests/types/cockroachdb_native_types.rs | 512 +++++++++++++ psl/psl/tests/types/mod.rs | 1 + psl/psl/tests/types/mssql_native_types.rs | 176 +++++ psl/psl/tests/types/mysql_native_types.rs | 531 ++++++++++++++ psl/psl/tests/types/postgres_native_types.rs | 499 +++++++++++++ psl/psl/tests/types/sqlite_native_types.rs | 487 ++++++++++++ .../mongodb/invalid_json_usage_in_type.prisma | 12 +- quaint/Cargo.toml | 40 +- quaint/src/ast.rs | 3 +- quaint/src/ast/column.rs | 6 +- quaint/src/ast/compare.rs | 329 ++++++++- quaint/src/ast/expression.rs | 90 +++ quaint/src/ast/function.rs | 16 + quaint/src/ast/function/geom_as_text.rs | 31 + quaint/src/ast/function/geom_from_text.rs | 41 ++ quaint/src/ast/row.rs | 75 ++ quaint/src/ast/values.rs | 88 ++- quaint/src/connector/mssql/conversion.rs | 0 .../src/connector/mssql/native/conversion.rs | 2 + .../src/connector/mysql/native/conversion.rs | 23 +- .../connector/postgres/native/conversion.rs | 25 + .../src/connector/sqlite/native/conversion.rs | 27 + quaint/src/connector/sqlite/native/mod.rs | 16 +- quaint/src/connector/type_identifier.rs | 1 + quaint/src/serde.rs | 0 quaint/src/visitor.rs | 67 ++ quaint/src/visitor/mssql.rs | 132 +++- quaint/src/visitor/mysql.rs | 75 ++ quaint/src/visitor/postgres.rs | 61 ++ quaint/src/visitor/sqlite.rs | 69 +- .../connector-test-kit-rs/qe-setup/src/lib.rs | 10 +- .../qe-setup/src/postgres.rs | 3 + .../qe-setup/src/sqlite.rs | 11 + .../src/schemas/geometry.rs | 25 + .../query-engine-tests/src/schemas/mod.rs | 2 + .../query-engine-tests/tests/new/metrics.rs | 4 +- .../tests/queries/filters/geometry_filter.rs | 123 ++++ .../tests/queries/filters/mod.rs | 1 + .../writes/data_types/native_types/mod.rs | 1 + .../writes/data_types/native_types/mongodb.rs | 5 +- .../writes/data_types/native_types/mysql.rs | 204 ++++++ .../data_types/native_types/postgres.rs | 392 ++++++++++ .../data_types/native_types/sql_server.rs | 12 +- .../writes/data_types/native_types/sqlite.rs | 160 ++++ .../writes/top_level_mutations/create.rs | 33 + .../src/connector_tag/mod.rs | 4 + .../src/connector_tag/postgres.rs | 3 + .../test-configs/postgis15 | 3 + .../mongodb-query-connector/src/filter.rs | 28 + .../mongodb-query-connector/src/value.rs | 17 +- .../connectors/sql-query-connector/Cargo.toml | 2 + .../sql-query-connector/src/filter/visitor.rs | 16 + .../src/model_extensions/scalar_field.rs | 42 +- .../src/query_builder/read.rs | 18 +- .../src/query_builder/write.rs | 1 + .../connectors/sql-query-connector/src/row.rs | 27 +- .../sql-query-connector/src/value.rs | 4 + .../sql-query-connector/src/value_ext.rs | 2 + query-engine/core/Cargo.toml | 1 + query-engine/core/src/constants.rs | 2 + .../core/src/query_document/parser.rs | 24 + .../extractors/filters/scalar.rs | 18 + query-engine/core/src/response_ir/internal.rs | 8 + .../src/ast_builders/datamodel_ast_builder.rs | 2 + .../schema_ast_builder/type_renderer.rs | 2 + query-engine/query-structure/src/field/mod.rs | 11 + .../query-structure/src/field/scalar.rs | 5 + .../query-structure/src/filter/compare.rs | 16 + .../src/filter/scalar/compare.rs | 132 ++++ .../src/filter/scalar/condition/mod.rs | 12 + .../query-structure/src/prisma_value_ext.rs | 4 +- .../graphql/schema_renderer/type_renderer.rs | 4 + .../fields/data_input_mapper/update.rs | 2 + .../input_types/fields/field_filter_types.rs | 16 + .../schema/src/build/input_types/mod.rs | 4 +- .../schema/src/build/output_types/field.rs | 4 +- query-engine/schema/src/constants.rs | 4 + query-engine/schema/src/input_types.rs | 8 + query-engine/schema/src/output_types.rs | 8 + query-engine/schema/src/query_schema.rs | 4 + .../src/flavour/postgres.rs | 5 + .../src/flavour/postgres/connection.rs | 4 + .../src/flavour/sqlite.rs | 8 + .../src/flavour/sqlite/connection.rs | 22 +- .../introspection_pair/scalar_field.rs | 2 + .../sql-schema-connector/src/lib.rs | 2 +- .../sql-schema-connector/src/sql_renderer.rs | 5 + .../src/sql_renderer/mssql_renderer.rs | 2 + .../src/sql_renderer/mysql_renderer.rs | 15 + .../src/sql_renderer/postgres_renderer.rs | 14 +- .../src/sql_renderer/sqlite_renderer.rs | 72 +- .../src/sql_schema_calculator.rs | 2 + .../sql_schema_differ_flavour/mssql.rs | 10 + .../sql_schema_differ_flavour/mysql.rs | 361 +++++++++ .../sql_schema_differ_flavour/postgres.rs | 8 + .../sql_schema_differ_flavour/sqlite.rs | 83 +++ .../tests/cockroachdb/gin.rs | 4 +- .../tests/commenting_out/cockroachdb.rs | 11 +- .../tests/native_types/mod.rs | 1 + .../tests/native_types/mssql.rs | 4 + .../tests/native_types/mysql.rs | 70 ++ .../tests/native_types/postgres.rs | 373 +++++++++- .../tests/native_types/sqlite.rs | 91 +++ .../mssql/geometry_should_be_unsupported.sql | 24 - .../migrations/indexes/cockroachdb/gin.rs | 4 +- .../tests/native_types/mssql.rs | 2 + .../tests/native_types/mysql.rs | 85 +-- schema-engine/sql-schema-describer/src/lib.rs | 6 + .../sql-schema-describer/src/mssql.rs | 3 + .../sql-schema-describer/src/mysql.rs | 82 ++- .../sql-schema-describer/src/postgres.rs | 101 ++- .../src/postgres/default.rs | 3 +- .../postgres/default/c_style_scalar_lists.rs | 1 + .../sql-schema-describer/src/sqlite.rs | 147 +++- .../tests/describers/mssql_describer_tests.rs | 38 + .../tests/describers/mysql_describer_tests.rs | 208 +++--- .../describers/postgres_describer_tests.rs | 199 ++++- .../cockroach_describer_tests.rs | 333 +++++++++ .../describers/sqlite_describer_tests.rs | 693 +++++++++++++++++- .../tests/test_api/mod.rs | 20 +- 155 files changed, 8503 insertions(+), 382 deletions(-) create mode 100644 .test_database_urls/postgis_15 create mode 100644 psl/builtin-connectors/src/geometry.rs create mode 100644 psl/builtin-connectors/src/sqlite_datamodel_connector/native_types.rs create mode 100644 psl/psl/tests/types/sqlite_native_types.rs create mode 100644 quaint/src/ast/function/geom_as_text.rs create mode 100644 quaint/src/ast/function/geom_from_text.rs create mode 100644 quaint/src/connector/mssql/conversion.rs create mode 100644 quaint/src/serde.rs create mode 100644 query-engine/connector-test-kit-rs/qe-setup/src/sqlite.rs create mode 100644 query-engine/connector-test-kit-rs/query-engine-tests/src/schemas/geometry.rs create mode 100644 query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs create mode 100644 query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sqlite.rs create mode 100644 query-engine/connector-test-kit-rs/test-configs/postgis15 create mode 100644 schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs delete mode 100644 schema-engine/sql-introspection-tests/tests/simple/mssql/geometry_should_be_unsupported.sql diff --git a/.github/workflows/test-query-engine.yml b/.github/workflows/test-query-engine.yml index 6d5e0ada4eb3..24f1032e6929 100644 --- a/.github/workflows/test-query-engine.yml +++ b/.github/workflows/test-query-engine.yml @@ -57,6 +57,22 @@ jobs: single_threaded: false connector: 'cockroachdb' version: '22.1' + - name: 'mysql_5_6' + single_threaded: true + connector: 'mysql' + version: '5.6' + - name: 'mysql_5_7' + single_threaded: true + connector: 'mysql' + version: '5.7' + - name: 'mysql_8' + single_threaded: true + connector: 'mysql' + version: '8' + - name: 'mysql_mariadb' + single_threaded: true + connector: 'mysql' + version: 'mariadb' engine_protocol: [graphql, json] env: diff --git a/.github/workflows/test-schema-engine.yml b/.github/workflows/test-schema-engine.yml index 425085d3af48..6b392f373ba6 100644 --- a/.github/workflows/test-schema-engine.yml +++ b/.github/workflows/test-schema-engine.yml @@ -86,6 +86,8 @@ jobs: url: 'postgresql://postgres:prisma@localhost:5437' - name: postgres15 url: 'postgresql://postgres:prisma@localhost:5438' + - name: postgis15 + url: 'postgresql://postgres:prisma@localhost:5439' - name: cockroach_23_1 url: 'postgresql://prisma@localhost:26260' - name: cockroach_22_2 diff --git a/.test_database_urls/postgis_15 b/.test_database_urls/postgis_15 new file mode 100644 index 000000000000..3bc64e1b6f69 --- /dev/null +++ b/.test_database_urls/postgis_15 @@ -0,0 +1 @@ +export TEST_DATABASE_URL="postgresql://postgres:prisma@localhost:5439" diff --git a/Cargo.lock b/Cargo.lock index 74f0b840d4f4..84356d6de794 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -99,6 +99,15 @@ version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + [[package]] name = "arrayvec" version = "0.5.2" @@ -1537,6 +1546,57 @@ dependencies = [ "version_check", ] +[[package]] +name = "geo-types" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9705398c5c7b26132e74513f4ee7c1d7dafd786004991b375c172be2be0eecaa" +dependencies = [ + "approx", + "num-traits", + "serde", +] + +[[package]] +name = "geojson" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d728c1df1fbf328d74151efe6cb0586f79ee813346ea981add69bd22c9241b" +dependencies = [ + "log", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "geozero" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "937818b9c084b253f929b5f5dbe050e744331d94ceb0a908b08873bcb2da3066" +dependencies = [ + "geo-types", + "geojson", + "log", + "serde_json", + "thiserror", + "wkt", +] + +[[package]] +name = "geozero" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b1b9a1eeae9ad09e12ec50243956105184b26440f81f978cd3aae009b214d4d" +dependencies = [ + "geojson", + "log", + "scroll", + "serde_json", + "thiserror", + "wkt", +] + [[package]] name = "getrandom" version = "0.1.16" @@ -2125,6 +2185,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "libm" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" + [[package]] name = "libsqlite3-sys" version = "0.26.0" @@ -2262,9 +2328,9 @@ checksum = "7e6bcd6433cff03a4bfc3d9834d504467db1f1cf6d0ea765d37d330249ed629d" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "memoffset" @@ -2822,6 +2888,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -3555,6 +3622,7 @@ dependencies = [ "connection-string", "either", "futures", + "geozero 0.11.0", "getrandom 0.2.10", "hex", "indoc 0.3.6", @@ -3572,6 +3640,7 @@ dependencies = [ "postgres-types", "quaint-test-macros", "quaint-test-setup", + "regex", "rusqlite", "serde", "serde_json", @@ -3658,6 +3727,7 @@ dependencies = [ "cuid", "enumflags2", "futures", + "geojson", "indexmap 1.9.3", "itertools", "lru 0.7.8", @@ -4092,14 +4162,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.3" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick 1.0.3", "memchr", - "regex-automata 0.3.6", - "regex-syntax 0.7.4", + "regex-automata 0.4.3", + "regex-syntax 0.8.2", ] [[package]] @@ -4113,13 +4183,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.6" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick 1.0.3", "memchr", - "regex-syntax 0.7.4", + "regex-syntax 0.8.2", ] [[package]] @@ -4130,9 +4200,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rend" @@ -4515,6 +4585,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scroll" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" + [[package]] name = "sct" version = "0.6.1" @@ -4939,6 +5015,7 @@ dependencies = [ "chrono", "cuid", "futures", + "geozero 0.10.0", "itertools", "once_cell", "opentelemetry", @@ -4948,6 +5025,7 @@ dependencies = [ "query-connector", "query-structure", "rand 0.7.3", + "regex", "serde", "serde_json", "thiserror", @@ -6353,6 +6431,18 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wkt" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c2252781f8927974e8ba6a67c965a759a2b88ea2b1825f6862426bbb1c8f41" +dependencies = [ + "geo-types", + "log", + "num-traits", + "thiserror", +] + [[package]] name = "wyz" version = "0.5.1" diff --git a/Makefile b/Makefile index 3aec261dc2f0..151a58ed4c2b 100644 --- a/Makefile +++ b/Makefile @@ -173,6 +173,12 @@ start-postgres15: dev-postgres15: start-postgres15 cp $(CONFIG_PATH)/postgres15 $(CONFIG_FILE) +start-postgis15: + docker compose -f docker-compose.yml up -d --remove-orphans postgis15 + +dev-postgis15: start-postgis15 + cp $(CONFIG_PATH)/postgis15 $(CONFIG_FILE) + start-cockroach_23_1: docker compose -f docker-compose.yml up --wait -d --remove-orphans cockroach_23_1 diff --git a/docker-compose.yml b/docker-compose.yml index b9694a2c7998..3ca0a85f6d43 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -213,6 +213,19 @@ services: networks: - databases + postgis15: + image: postgis/postgis:15-3.3 + restart: always + command: postgres -c 'max_connections=1000' + environment: + POSTGRES_PASSWORD: "prisma" + POSTGRES_HOST_AUTH_METHOD: "md5" + POSTGRES_INITDB_ARGS: "--auth-host=md5" + ports: + - "5439:5432" + networks: + - databases + mysql-5-6: image: mysql:5.6.50 command: mysqld diff --git a/libs/prisma-value/src/lib.rs b/libs/prisma-value/src/lib.rs index d797605ecccc..2d61a73bea91 100644 --- a/libs/prisma-value/src/lib.rs +++ b/libs/prisma-value/src/lib.rs @@ -24,6 +24,8 @@ pub enum PrismaValue { Uuid(Uuid), List(PrismaListValue), Json(String), + GeoJson(String), + Geometry(String), /// A collections of key-value pairs constituting an object. #[serde(serialize_with = "serialize_object")] @@ -318,6 +320,8 @@ impl fmt::Display for PrismaValue { PrismaValue::Null => "null".fmt(f), PrismaValue::Uuid(x) => x.fmt(f), PrismaValue::Json(x) => x.fmt(f), + PrismaValue::GeoJson(x) => x.fmt(f), + PrismaValue::Geometry(x) => x.fmt(f), PrismaValue::BigInt(x) => x.fmt(f), PrismaValue::List(x) => { let as_string = format!("{x:?}"); diff --git a/libs/test-setup/src/postgres.rs b/libs/test-setup/src/postgres.rs index 11b62700504b..e547c847ca49 100644 --- a/libs/test-setup/src/postgres.rs +++ b/libs/test-setup/src/postgres.rs @@ -7,9 +7,14 @@ pub(crate) fn get_postgres_tags(database_url: &str) -> Result, St let fut = async { let quaint = Quaint::new(database_url).await.map_err(|err| err.to_string())?; let mut tags = Tags::Postgres.into(); - let version = quaint.version().await.map_err(|err| err.to_string())?; - match version { + if let Ok(_postgis_version) = quaint.query_raw("SELECT PostGIS_version()", &[]).await { + tags |= Tags::PostGIS; + } + + let postgres_version = quaint.version().await.map_err(|err| err.to_string())?; + + match postgres_version { None => Ok(tags), Some(version) => { eprintln!("version: {version:?}"); diff --git a/libs/test-setup/src/sqlite.rs b/libs/test-setup/src/sqlite.rs index 869fdf990480..33c006e2dfe2 100644 --- a/libs/test-setup/src/sqlite.rs +++ b/libs/test-setup/src/sqlite.rs @@ -1,4 +1,8 @@ +use enumflags2::BitFlags; use once_cell::sync::Lazy; +use quaint::{prelude::Queryable, single::Quaint}; + +use crate::{runtime::run_with_thread_local_runtime as tok, Tags}; pub fn sqlite_test_url(db_name: &str) -> String { std::env::var("SQLITE_TEST_URL").unwrap_or_else(|_| format!("file:{}", sqlite_test_file(db_name))) @@ -25,3 +29,17 @@ fn sqlite_test_file(db_name: &str) -> String { file_path.to_string_lossy().into_owned() } + +pub(crate) fn get_sqlite_tags() -> Result, String> { + let fut = async { + let mut tags: BitFlags = Tags::Sqlite.into(); + // The SpatiaLite extension is loaded by quaint, assuming the SPATIALITE_PATH env variable is set + // If the extension can be loaded in a dummy database, it means it will also be available for the tests + let quaint = Quaint::new_in_memory().map_err(|err| err.to_string())?; + if let Ok(_has_spatialite) = quaint.query_raw("SELECT spatialite_version();", &[]).await { + tags |= Tags::Spatialite; + } + Ok(tags) + }; + tok(fut) +} diff --git a/libs/test-setup/src/tags.rs b/libs/test-setup/src/tags.rs index ed5720234986..26f9e5767ced 100644 --- a/libs/test-setup/src/tags.rs +++ b/libs/test-setup/src/tags.rs @@ -41,6 +41,8 @@ tags![ CockroachDb221 = 1 << 19, CockroachDb222 = 1 << 20, CockroachDb231 = 1 << 21, + PostGIS = 1 << 22, + Spatialite = 1 << 23, ]; pub fn tags_from_comma_separated_list(input: &str) -> BitFlags { diff --git a/libs/test-setup/src/test_api_args.rs b/libs/test-setup/src/test_api_args.rs index 28f645729409..f3e5fb8bfa2a 100644 --- a/libs/test-setup/src/test_api_args.rs +++ b/libs/test-setup/src/test_api_args.rs @@ -1,4 +1,4 @@ -use crate::{logging, mssql, mysql, postgres, Capabilities, Tags}; +use crate::{logging, mssql, mysql, postgres, sqlite, Capabilities, Tags}; use enumflags2::BitFlags; use once_cell::sync::Lazy; use quaint::single::Quaint; @@ -41,7 +41,7 @@ static DB_UNDER_TEST: Lazy> = Lazy::new(|| { match prefix { "file" | "sqlite" => Ok(DbUnderTest { database_url, - tags: Tags::Sqlite.into(), + tags: sqlite::get_sqlite_tags()?, capabilities: Capabilities::CreateDatabase.into(), provider: "sqlite", shadow_database_url, diff --git a/prisma-fmt/tests/native_types.rs b/prisma-fmt/tests/native_types.rs index f33e4b52a07e..25e4f4ad5181 100644 --- a/prisma-fmt/tests/native_types.rs +++ b/prisma-fmt/tests/native_types.rs @@ -11,7 +11,7 @@ fn test_native_types_list_on_crdb() { let result = prisma_fmt::native_types(schema.to_owned()); let expected = expect![[ - r#"[{"name":"Bit","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Bool","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Boolean"]},{"name":"Bytes","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Bytes"]},{"name":"Char","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Date","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["DateTime"]},{"name":"Decimal","_number_of_args":0,"_number_of_optional_args":2,"prisma_types":["Decimal"]},{"name":"Float4","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Float"]},{"name":"Float8","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Float"]},{"name":"Inet","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"Int2","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Int"]},{"name":"Int4","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Int"]},{"name":"Int8","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["BigInt"]},{"name":"JsonB","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Json"]},{"name":"Oid","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Int"]},{"name":"CatalogSingleChar","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"String","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Time","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Timestamp","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Timestamptz","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Timetz","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Uuid","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"VarBit","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]}]"# + r#"[{"name":"Bit","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Bool","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Boolean"]},{"name":"Bytes","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Bytes"]},{"name":"Char","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Date","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["DateTime"]},{"name":"Decimal","_number_of_args":0,"_number_of_optional_args":2,"prisma_types":["Decimal"]},{"name":"Float4","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Float"]},{"name":"Float8","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Float"]},{"name":"Inet","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"Int2","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Int"]},{"name":"Int4","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Int"]},{"name":"Int8","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["BigInt"]},{"name":"JsonB","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Json"]},{"name":"Oid","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Int"]},{"name":"CatalogSingleChar","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"String","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Time","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Timestamp","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Timestamptz","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Timetz","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Uuid","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"VarBit","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Geometry","_number_of_args":0,"_number_of_optional_args":2,"prisma_types":["Geometry","GeoJson"]},{"name":"Geography","_number_of_args":0,"_number_of_optional_args":2,"prisma_types":["Geometry","GeoJson"]}]"# ]]; expected.assert_eq(&result); } diff --git a/psl/builtin-connectors/src/cockroach_datamodel_connector.rs b/psl/builtin-connectors/src/cockroach_datamodel_connector.rs index 5456deb59df6..54084a5512b8 100644 --- a/psl/builtin-connectors/src/cockroach_datamodel_connector.rs +++ b/psl/builtin-connectors/src/cockroach_datamodel_connector.rs @@ -1,6 +1,7 @@ mod native_types; mod validations; +pub use crate::geometry::GeometryParams; pub use native_types::CockroachType; use enumflags2::BitFlags; @@ -22,7 +23,7 @@ use psl_core::{ }; use std::borrow::Cow; -use crate::completions; +use crate::{completions, geometry::GeometryType}; const CONSTRAINT_SCOPES: &[ConstraintScope] = &[ConstraintScope::ModelPrimaryKeyKeyIndexForeignKey]; @@ -42,6 +43,12 @@ const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(Connector Json | JsonFiltering | JsonFilteringArrayPath | + EwktGeometry | + GeoJsonGeometry | + GeometryRawRead | + GeometryFiltering | + GeometryExtraDims | + GeometryExtraTypes | NamedPrimaryKeys | NamedForeignKeys | SqlQueryRaw | @@ -71,6 +78,20 @@ const SCALAR_TYPE_DEFAULTS: &[(ScalarType, CockroachType)] = &[ (ScalarType::DateTime, CockroachType::Timestamp(Some(3))), (ScalarType::Bytes, CockroachType::Bytes), (ScalarType::Json, CockroachType::JsonB), + ( + ScalarType::Geometry, + CockroachType::Geometry(Some(GeometryParams { + ty: GeometryType::Geometry, + srid: 0, + })), + ), + ( + ScalarType::GeoJson, + CockroachType::Geometry(Some(GeometryParams { + ty: GeometryType::Geometry, + srid: 4326, + })), + ), ]; pub(crate) struct CockroachDatamodelConnector; @@ -136,6 +157,9 @@ impl Connector for CockroachDatamodelConnector { CockroachType::JsonB => ScalarType::Json, // Bytes CockroachType::Bytes => ScalarType::Bytes, + // Geometry + CockroachType::Geometry(_) => ScalarType::Geometry, + CockroachType::Geography(_) => ScalarType::Geometry, } } @@ -169,7 +193,7 @@ impl Connector for CockroachDatamodelConnector { fn validate_native_type_arguments( &self, native_type_instance: &NativeTypeInstance, - _scalar_type: &ScalarType, + scalar_type: &ScalarType, span: ast::Span, errors: &mut Diagnostics, ) { @@ -189,6 +213,19 @@ impl Connector for CockroachDatamodelConnector { CockroachType::Bit(Some(0)) | CockroachType::VarBit(Some(0)) => { errors.push_error(error.new_argument_m_out_of_range_error("M must be a positive integer.", span)) } + CockroachType::Geometry(Some(g)) | CockroachType::Geography(Some(g)) + if *scalar_type == ScalarType::GeoJson && g.srid != 4326 => + { + errors.push_error(error.new_argument_m_out_of_range_error("GeoJson SRID must be 4326.", span)) + } + CockroachType::Geometry(Some(g)) | CockroachType::Geography(Some(g)) if g.srid < 0 || g.srid > 999000 => { + errors.push_error(error.new_argument_m_out_of_range_error("SRID must be between 0 and 999000.", span)) + } + CockroachType::Geometry(Some(g)) | CockroachType::Geography(Some(g)) if g.ty.is_extra() => errors + .push_error(error.new_argument_m_out_of_range_error( + &format!("{} isn't supported for the current connector.", g.ty), + span, + )), CockroachType::Timestamp(Some(p)) | CockroachType::Timestamptz(Some(p)) | CockroachType::Time(Some(p)) diff --git a/psl/builtin-connectors/src/cockroach_datamodel_connector/native_types.rs b/psl/builtin-connectors/src/cockroach_datamodel_connector/native_types.rs index 0fb8f523b5b0..5c03e226cb6b 100644 --- a/psl/builtin-connectors/src/cockroach_datamodel_connector/native_types.rs +++ b/psl/builtin-connectors/src/cockroach_datamodel_connector/native_types.rs @@ -1,3 +1,5 @@ +use crate::geometry::GeometryParams; + crate::native_type_definition! { CockroachType; Bit(Option) -> String, @@ -22,4 +24,6 @@ crate::native_type_definition! { Timetz(Option) -> DateTime, Uuid -> String, VarBit(Option) -> String, + Geometry(Option) -> Geometry | GeoJson, + Geography(Option) -> Geometry | GeoJson, } diff --git a/psl/builtin-connectors/src/geometry.rs b/psl/builtin-connectors/src/geometry.rs new file mode 100644 index 000000000000..522eaa202e14 --- /dev/null +++ b/psl/builtin-connectors/src/geometry.rs @@ -0,0 +1,355 @@ +use std::{fmt, str::FromStr}; + +#[derive(Debug, Default, Clone, Copy, PartialEq)] +pub struct GeometryParams { + pub ty: GeometryType, + pub srid: i32, +} + +#[repr(u32)] +#[derive(Debug, Default, Clone, Copy, PartialEq, PartialOrd)] +pub enum GeometryType { + #[default] + Geometry = 0, + Point = 1, + LineString = 2, + Polygon = 3, + MultiPoint = 4, + MultiLineString = 5, + MultiPolygon = 6, + GeometryCollection = 7, + CircularString = 8, + CompoundCurve = 9, + CurvePolygon = 10, + MultiCurve = 11, + MultiSurface = 12, + // Curve = 13, + // Surface = 14,, + PolyhedralSurface = 15, + Tin = 16, + Triangle = 17, + GeometryZ = 1000, + PointZ = 1001, + LineStringZ = 1002, + PolygonZ = 1003, + MultiPointZ = 1004, + MultiLineStringZ = 1005, + MultiPolygonZ = 1006, + GeometryCollectionZ = 1007, + CircularStringZ = 1008, + CompoundCurveZ = 1009, + CurvePolygonZ = 1010, + MultiCurveZ = 1011, + MultiSurfaceZ = 1012, + // CurveZ = 1013, + // SurfaceZ = 1014, + PolyhedralSurfaceZ = 1015, + TinZ = 1016, + TriangleZ = 1017, + GeometryM = 2000, + PointM = 2001, + LineStringM = 2002, + PolygonM = 2003, + MultiPointM = 2004, + MultiLineStringM = 2005, + MultiPolygonM = 2006, + GeometryCollectionM = 2007, + CircularStringM = 2008, + CompoundCurveM = 2009, + CurvePolygonM = 2010, + MultiCurveM = 2011, + MultiSurfaceM = 2012, + // CurveM = 2013, + // SurfaceM = 2014, + PolyhedralSurfaceM = 2015, + TinM = 2016, + TriangleM = 2017, + GeometryZM = 3000, + PointZM = 3001, + LineStringZM = 3002, + PolygonZM = 3003, + MultiPointZM = 3004, + MultiLineStringZM = 3005, + MultiPolygonZM = 3006, + GeometryCollectionZM = 3007, + CircularStringZM = 3008, + CompoundCurveZM = 3009, + CurvePolygonZM = 3010, + MultiCurveZM = 3011, + MultiSurfaceZM = 3012, + // CurveZM = 3013, + // SurfaceZM = 3014, + PolyhedralSurfaceZM = 3015, + TinZM = 3016, + TriangleZM = 3017, +} + +impl GeometryType { + pub fn is_extra(&self) -> bool { + self.as_2d() > Self::GeometryCollection + } + + pub fn as_2d(&self) -> Self { + Self::try_from(*self as u32 % 1000).unwrap() + } + + pub fn dimensions(&self) -> &'static str { + match *self as u32 / 1000 { + 0 => "XY", + 1 => "XYZ", + 2 => "XYM", + 3 => "XYZM", + _ => unreachable!(), + } + } +} + +impl TryFrom for GeometryType { + type Error = String; + + fn try_from(value: u32) -> Result { + match value { + 0 => Ok(Self::Geometry), + 1 => Ok(Self::Point), + 2 => Ok(Self::LineString), + 3 => Ok(Self::Polygon), + 4 => Ok(Self::MultiPoint), + 5 => Ok(Self::MultiLineString), + 6 => Ok(Self::MultiPolygon), + 7 => Ok(Self::GeometryCollection), + 8 => Ok(Self::CircularString), + 9 => Ok(Self::CompoundCurve), + 10 => Ok(Self::CurvePolygon), + 11 => Ok(Self::MultiCurve), + 12 => Ok(Self::MultiSurface), + // 13 => Ok(Self::Curve), + // 14 => Ok(Self::Surface), + 15 => Ok(Self::PolyhedralSurface), + 16 => Ok(Self::Tin), + 17 => Ok(Self::Triangle), + 1000 => Ok(Self::GeometryZ), + 1001 => Ok(Self::PointZ), + 1002 => Ok(Self::LineStringZ), + 1003 => Ok(Self::PolygonZ), + 1004 => Ok(Self::MultiPointZ), + 1005 => Ok(Self::MultiLineStringZ), + 1006 => Ok(Self::MultiPolygonZ), + 1007 => Ok(Self::GeometryCollectionZ), + 1008 => Ok(Self::CircularStringZ), + 1009 => Ok(Self::CompoundCurveZ), + 1010 => Ok(Self::CurvePolygonZ), + 1011 => Ok(Self::MultiCurveZ), + 1012 => Ok(Self::MultiSurfaceZ), + // 1013 => Ok(Self::CurveZ), + // 1014 => Ok(Self::SurfaceZ), + 1015 => Ok(Self::PolyhedralSurfaceZ), + 1016 => Ok(Self::TinZ), + 1017 => Ok(Self::TriangleZ), + 2000 => Ok(Self::GeometryM), + 2001 => Ok(Self::PointM), + 2002 => Ok(Self::LineStringM), + 2003 => Ok(Self::PolygonM), + 2004 => Ok(Self::MultiPointM), + 2005 => Ok(Self::MultiLineStringM), + 2006 => Ok(Self::MultiPolygonM), + 2007 => Ok(Self::GeometryCollectionM), + 2008 => Ok(Self::CircularStringM), + 2009 => Ok(Self::CompoundCurveM), + 2010 => Ok(Self::CurvePolygonM), + 2011 => Ok(Self::MultiCurveM), + 2012 => Ok(Self::MultiSurfaceM), + // 2013 => Ok(Self::CurveM), + // 2014 => Ok(Self::SurfaceM), + 2015 => Ok(Self::PolyhedralSurfaceM), + 2016 => Ok(Self::TinM), + 2017 => Ok(Self::TriangleM), + 3000 => Ok(Self::GeometryZM), + 3001 => Ok(Self::PointZM), + 3002 => Ok(Self::LineStringZM), + 3003 => Ok(Self::PolygonZM), + 3004 => Ok(Self::MultiPointZM), + 3005 => Ok(Self::MultiLineStringZM), + 3006 => Ok(Self::MultiPolygonZM), + 3007 => Ok(Self::GeometryCollectionZM), + 3008 => Ok(Self::CircularStringZM), + 3009 => Ok(Self::CompoundCurveZM), + 3010 => Ok(Self::CurvePolygonZM), + 3011 => Ok(Self::MultiCurveZM), + 3012 => Ok(Self::MultiSurfaceZM), + // 3013 => Ok(Self::CurveZM), + // 3014 => Ok(Self::SurfaceZM), + 3015 => Ok(Self::PolyhedralSurfaceZM), + 3016 => Ok(Self::TinZM), + 3017 => Ok(Self::TriangleZM), + i => Err(format!("Invalid geometry type code: {i}")), + } + } +} + +impl FromStr for GeometryType { + type Err = String; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "geometry" => Ok(GeometryType::Geometry), + "geometrym" => Ok(GeometryType::GeometryM), + "geometryz" => Ok(GeometryType::GeometryZ), + "geometryzm" => Ok(GeometryType::GeometryZM), + "point" => Ok(GeometryType::Point), + "pointm" => Ok(GeometryType::PointM), + "pointz" => Ok(GeometryType::PointZ), + "pointzm" => Ok(GeometryType::PointZM), + "linestring" => Ok(GeometryType::LineString), + "linestringm" => Ok(GeometryType::LineStringM), + "linestringz" => Ok(GeometryType::LineStringZ), + "linestringzm" => Ok(GeometryType::LineStringZM), + "polygon" => Ok(GeometryType::Polygon), + "polygonm" => Ok(GeometryType::PolygonM), + "polygonz" => Ok(GeometryType::PolygonZ), + "polygonzm" => Ok(GeometryType::PolygonZM), + "multipoint" => Ok(GeometryType::MultiPoint), + "multipointm" => Ok(GeometryType::MultiPointM), + "multipointz" => Ok(GeometryType::MultiPointZ), + "multipointzm" => Ok(GeometryType::MultiPointZM), + "multilinestring" => Ok(GeometryType::MultiLineString), + "multilinestringm" => Ok(GeometryType::MultiLineStringM), + "multilinestringz" => Ok(GeometryType::MultiLineStringZ), + "multilinestringzm" => Ok(GeometryType::MultiLineStringZM), + "multipolygon" => Ok(GeometryType::MultiPolygon), + "multipolygonm" => Ok(GeometryType::MultiPolygonM), + "multipolygonz" => Ok(GeometryType::MultiPolygonZ), + "multipolygonzm" => Ok(GeometryType::MultiPolygonZM), + "geometrycollection" => Ok(GeometryType::GeometryCollection), + "geometrycollectionm" => Ok(GeometryType::GeometryCollectionM), + "geometrycollectionz" => Ok(GeometryType::GeometryCollectionZ), + "geometrycollectionzm" => Ok(GeometryType::GeometryCollectionZM), + "circularstring" => Ok(GeometryType::CircularString), + "circularstringm" => Ok(GeometryType::CircularStringM), + "circularstringz" => Ok(GeometryType::CircularStringZ), + "circularstringzm" => Ok(GeometryType::CircularStringZM), + "compoundcurve" => Ok(GeometryType::CompoundCurve), + "compoundcurvem" => Ok(GeometryType::CompoundCurveM), + "compoundcurvez" => Ok(GeometryType::CompoundCurveZ), + "compoundcurvezm" => Ok(GeometryType::CompoundCurveZM), + "curvepolygon" => Ok(GeometryType::CurvePolygon), + "curvepolygonm" => Ok(GeometryType::CurvePolygonM), + "curvepolygonz" => Ok(GeometryType::CurvePolygonZ), + "curvepolygonzm" => Ok(GeometryType::CurvePolygonZM), + "multicurve" => Ok(GeometryType::MultiCurve), + "multicurvem" => Ok(GeometryType::MultiCurveM), + "multicurvez" => Ok(GeometryType::MultiCurveZ), + "multicurvezm" => Ok(GeometryType::MultiCurveZM), + "multisurface" => Ok(GeometryType::MultiSurface), + "multisurfacem" => Ok(GeometryType::MultiSurfaceM), + "multisurfacez" => Ok(GeometryType::MultiSurfaceZ), + "multisurfacezm" => Ok(GeometryType::MultiSurfaceZM), + "polyhedralsurface" => Ok(GeometryType::PolyhedralSurface), + "polyhedralsurfacem" => Ok(GeometryType::PolyhedralSurfaceM), + "polyhedralsurfacez" => Ok(GeometryType::PolyhedralSurfaceZ), + "polyhedralsurfacezm" => Ok(GeometryType::PolyhedralSurfaceZM), + "triangle" => Ok(GeometryType::Triangle), + "trianglem" => Ok(GeometryType::TriangleM), + "trianglez" => Ok(GeometryType::TriangleZ), + "trianglezm" => Ok(GeometryType::TriangleZM), + "tin" => Ok(GeometryType::Tin), + "tinm" => Ok(GeometryType::TinM), + "tinz" => Ok(GeometryType::TinZ), + "tinzm" => Ok(GeometryType::TinZM), + _ => Err(format!("{} is not a valid geometry type.", s)), + } + } +} + +impl fmt::Display for GeometryType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + GeometryType::Geometry => write!(f, "Geometry"), + GeometryType::GeometryM => write!(f, "GeometryM"), + GeometryType::GeometryZ => write!(f, "GeometryZ"), + GeometryType::GeometryZM => write!(f, "GeometryZM"), + GeometryType::Point => write!(f, "Point"), + GeometryType::PointM => write!(f, "PointM"), + GeometryType::PointZ => write!(f, "PointZ"), + GeometryType::PointZM => write!(f, "PointZM"), + GeometryType::LineString => write!(f, "LineString"), + GeometryType::LineStringM => write!(f, "LineStringM"), + GeometryType::LineStringZ => write!(f, "LineStringZ"), + GeometryType::LineStringZM => write!(f, "LineStringZM"), + GeometryType::Polygon => write!(f, "Polygon"), + GeometryType::PolygonM => write!(f, "PolygonM"), + GeometryType::PolygonZ => write!(f, "PolygonZ"), + GeometryType::PolygonZM => write!(f, "PolygonZM"), + GeometryType::MultiPoint => write!(f, "MultiPoint"), + GeometryType::MultiPointM => write!(f, "MultiPointM"), + GeometryType::MultiPointZ => write!(f, "MultiPointZ"), + GeometryType::MultiPointZM => write!(f, "MultiPointZM"), + GeometryType::MultiLineString => write!(f, "MultiLineString"), + GeometryType::MultiLineStringM => write!(f, "MultiLineStringM"), + GeometryType::MultiLineStringZ => write!(f, "MultiLineStringZ"), + GeometryType::MultiLineStringZM => write!(f, "MultiLineStringZM"), + GeometryType::MultiPolygon => write!(f, "MultiPolygon"), + GeometryType::MultiPolygonM => write!(f, "MultiPolygonM"), + GeometryType::MultiPolygonZ => write!(f, "MultiPolygonZ"), + GeometryType::MultiPolygonZM => write!(f, "MultiPolygonZM"), + GeometryType::GeometryCollection => write!(f, "GeometryCollection"), + GeometryType::GeometryCollectionM => write!(f, "GeometryCollectionM"), + GeometryType::GeometryCollectionZ => write!(f, "GeometryCollectionZ"), + GeometryType::GeometryCollectionZM => write!(f, "GeometryCollectionZM"), + GeometryType::CircularString => write!(f, "CircularString"), + GeometryType::CircularStringM => write!(f, "CircularStringM"), + GeometryType::CircularStringZ => write!(f, "CircularStringZ"), + GeometryType::CircularStringZM => write!(f, "CircularStringZM"), + GeometryType::CompoundCurve => write!(f, "CompoundCurve"), + GeometryType::CompoundCurveM => write!(f, "CompoundCurveM"), + GeometryType::CompoundCurveZ => write!(f, "CompoundCurveZ"), + GeometryType::CompoundCurveZM => write!(f, "CompoundCurveZM"), + GeometryType::CurvePolygon => write!(f, "CurvePolygon"), + GeometryType::CurvePolygonM => write!(f, "CurvePolygonM"), + GeometryType::CurvePolygonZ => write!(f, "CurvePolygonZ"), + GeometryType::CurvePolygonZM => write!(f, "CurvePolygonZM"), + GeometryType::MultiCurve => write!(f, "MultiCurve"), + GeometryType::MultiCurveM => write!(f, "MultiCurveM"), + GeometryType::MultiCurveZ => write!(f, "MultiCurveZ"), + GeometryType::MultiCurveZM => write!(f, "MultiCurveZM"), + GeometryType::MultiSurface => write!(f, "MultiSurface"), + GeometryType::MultiSurfaceM => write!(f, "MultiSurfaceM"), + GeometryType::MultiSurfaceZ => write!(f, "MultiSurfaceZ"), + GeometryType::MultiSurfaceZM => write!(f, "MultiSurfaceZM"), + GeometryType::PolyhedralSurface => write!(f, "PolyhedralSurface"), + GeometryType::PolyhedralSurfaceM => write!(f, "PolyhedralSurfaceM"), + GeometryType::PolyhedralSurfaceZ => write!(f, "PolyhedralSurfaceZ"), + GeometryType::PolyhedralSurfaceZM => write!(f, "PolyhedralSurfaceZM"), + GeometryType::Triangle => write!(f, "Triangle"), + GeometryType::TriangleM => write!(f, "TriangleM"), + GeometryType::TriangleZ => write!(f, "TriangleZ"), + GeometryType::TriangleZM => write!(f, "TriangleZM"), + GeometryType::Tin => write!(f, "Tin"), + GeometryType::TinM => write!(f, "TinM"), + GeometryType::TinZ => write!(f, "TinZ"), + GeometryType::TinZM => write!(f, "TinZM"), + } + } +} + +impl psl_core::datamodel_connector::NativeTypeArguments for GeometryParams { + const DESCRIPTION: &'static str = "a geometry type and an optional srid"; + const OPTIONAL_ARGUMENTS_COUNT: usize = 0; + const REQUIRED_ARGUMENTS_COUNT: usize = 2; + + fn from_parts(parts: &[String]) -> Option { + match parts { + [geom] => GeometryType::from_str(geom).ok().map(|ty| Self { ty, srid: 0 }), + [geom, srid] => GeometryType::from_str(geom) + .ok() + .and_then(|ty| srid.parse().ok().map(|srid| Self { ty, srid })), + _ => None, + } + } + + fn to_parts(&self) -> Vec { + match self.srid { + 0 => vec![self.ty.to_string()], + srid => vec![self.ty.to_string(), srid.to_string()], + } + } +} diff --git a/psl/builtin-connectors/src/lib.rs b/psl/builtin-connectors/src/lib.rs index c477386a23ed..a890ef5d2acd 100644 --- a/psl/builtin-connectors/src/lib.rs +++ b/psl/builtin-connectors/src/lib.rs @@ -5,11 +5,14 @@ pub mod cockroach_datamodel_connector; pub mod completions; pub use cockroach_datamodel_connector::CockroachType; +pub use geometry::{GeometryParams, GeometryType}; pub use mongodb::MongoDbType; pub use mssql_datamodel_connector::{MsSqlType, MsSqlTypeParameter}; pub use mysql_datamodel_connector::MySqlType; pub use postgres_datamodel_connector::{PostgresDatasourceProperties, PostgresType}; +pub use sqlite_datamodel_connector::SQLiteType; +mod geometry; mod mongodb; mod mssql_datamodel_connector; mod mysql_datamodel_connector; diff --git a/psl/builtin-connectors/src/mongodb.rs b/psl/builtin-connectors/src/mongodb.rs index e2e820f6b166..068a92e28571 100644 --- a/psl/builtin-connectors/src/mongodb.rs +++ b/psl/builtin-connectors/src/mongodb.rs @@ -17,6 +17,7 @@ use std::result::Result as StdResult; const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(ConnectorCapability::{ Json | + GeoJsonGeometry | Enums | EnumArrayPush | RelationFieldsInArbitraryOrder | diff --git a/psl/builtin-connectors/src/mongodb/mongodb_types.rs b/psl/builtin-connectors/src/mongodb/mongodb_types.rs index c75a7f0b3bd4..dc3dc82f5b81 100644 --- a/psl/builtin-connectors/src/mongodb/mongodb_types.rs +++ b/psl/builtin-connectors/src/mongodb/mongodb_types.rs @@ -16,7 +16,7 @@ crate::native_type_definition! { Int -> Int, Timestamp -> DateTime, Long -> Int | BigInt, - Json -> Json, + Json -> Json | GeoJson, // Deprecated: // DbPointer // Undefined @@ -42,6 +42,7 @@ static DEFAULT_MAPPING: Lazy> = Lazy::new(|| { (ScalarType::DateTime, MongoDbType::Timestamp), (ScalarType::Bytes, MongoDbType::BinData), (ScalarType::Json, MongoDbType::Json), + (ScalarType::GeoJson, MongoDbType::Json), ] .into_iter() .collect() diff --git a/psl/builtin-connectors/src/mssql_datamodel_connector.rs b/psl/builtin-connectors/src/mssql_datamodel_connector.rs index 46647fabe8af..a9879c18778d 100644 --- a/psl/builtin-connectors/src/mssql_datamodel_connector.rs +++ b/psl/builtin-connectors/src/mssql_datamodel_connector.rs @@ -28,6 +28,9 @@ const CONSTRAINT_SCOPES: &[ConstraintScope] = &[ ]; const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(ConnectorCapability::{ + EwktGeometry | + GeoJsonGeometry | + GeometryFiltering | AnyId | AutoIncrement | AutoIncrementAllowedOnNonId | @@ -73,6 +76,8 @@ const SCALAR_TYPE_DEFAULTS: &[(ScalarType, MsSqlType)] = &[ ScalarType::Json, MsSqlType::NVarChar(Some(MsSqlTypeParameter::Number(1000))), ), + (ScalarType::Geometry, MsSqlType::Geometry), + (ScalarType::GeoJson, MsSqlType::Geometry), ]; impl Connector for MsSqlDatamodelConnector { @@ -138,6 +143,9 @@ impl Connector for MsSqlDatamodelConnector { VarBinary(_) => ScalarType::Bytes, Image => ScalarType::Bytes, Bit => ScalarType::Bytes, + //Geometry + Geometry => ScalarType::Geometry, + Geography => ScalarType::Geometry, } } @@ -327,5 +335,7 @@ pub(crate) fn heap_allocated_types() -> &'static [MsSqlType] { VarBinary(Some(Max)), VarChar(Some(Max)), NVarChar(Some(Max)), + Geometry, + Geography, ] } diff --git a/psl/builtin-connectors/src/mssql_datamodel_connector/native_types.rs b/psl/builtin-connectors/src/mssql_datamodel_connector/native_types.rs index 06898c2ee08a..04f6d880646f 100644 --- a/psl/builtin-connectors/src/mssql_datamodel_connector/native_types.rs +++ b/psl/builtin-connectors/src/mssql_datamodel_connector/native_types.rs @@ -104,4 +104,6 @@ crate::native_type_definition! { /// GUID, which is UUID but Microsoft invented them so they have their own /// term for it. UniqueIdentifier -> String, + Geometry -> Geometry | GeoJson, + Geography -> Geometry | GeoJson, } diff --git a/psl/builtin-connectors/src/mysql_datamodel_connector.rs b/psl/builtin-connectors/src/mysql_datamodel_connector.rs index 39995fb5d48d..1ad5fe753133 100644 --- a/psl/builtin-connectors/src/mysql_datamodel_connector.rs +++ b/psl/builtin-connectors/src/mysql_datamodel_connector.rs @@ -25,11 +25,23 @@ const TINY_TEXT_TYPE_NAME: &str = "TinyText"; const TEXT_TYPE_NAME: &str = "Text"; const MEDIUM_TEXT_TYPE_NAME: &str = "MediumText"; const LONG_TEXT_TYPE_NAME: &str = "LongText"; +const GEOMETRY_TYPE_NAME: &str = "Geometry"; +const POINT_TYPE_NAME: &str = "Point"; +const LINESTRING_TYPE_NAME: &str = "LineString"; +const POLYGON_TYPE_NAME: &str = "Polygon"; +const MULTIPOINT_TYPE_NAME: &str = "MultiPoint"; +const MULTILINESTRING_TYPE_NAME: &str = "MultiLineString"; +const MULTIPOLYGON_TYPE_NAME: &str = "MultiPolygon"; +const GEOMETRYCOLLECTION_TYPE_NAME: &str = "GeometryCollection"; const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(ConnectorCapability::{ Enums | EnumArrayPush | Json | + EwktGeometry | + GeoJsonGeometry | + GeometryRawRead | + GeometryFiltering | AutoIncrementAllowedOnNonId | RelationFieldsInArbitraryOrder | CreateMany | @@ -76,6 +88,9 @@ const SCALAR_TYPE_DEFAULTS: &[(ScalarType, MySqlType)] = &[ (ScalarType::DateTime, MySqlType::DateTime(Some(3))), (ScalarType::Bytes, MySqlType::LongBlob), (ScalarType::Json, MySqlType::Json), + (ScalarType::Geometry, MySqlType::Geometry(None)), + // TODO@geometry In MYSQL8+, ideally we'd set the default SRID to 4326 + (ScalarType::GeoJson, MySqlType::Geometry(None)), ]; impl Connector for MySqlDatamodelConnector { @@ -146,6 +161,15 @@ impl Connector for MySqlDatamodelConnector { Blob => ScalarType::Bytes, MediumBlob => ScalarType::Bytes, Bit(_) => ScalarType::Bytes, + //Geometry + Geometry(_) => ScalarType::Geometry, + Point(_) => ScalarType::Geometry, + LineString(_) => ScalarType::Geometry, + Polygon(_) => ScalarType::Geometry, + MultiPoint(_) => ScalarType::Geometry, + MultiLineString(_) => ScalarType::Geometry, + MultiPolygon(_) => ScalarType::Geometry, + GeometryCollection(_) => ScalarType::Geometry, //Missing from docs UnsignedInt => ScalarType::Int, UnsignedSmallInt => ScalarType::Int, @@ -207,6 +231,19 @@ impl Connector for MySqlDatamodelConnector { VarChar(length) if *length > 65535 => { errors.push_error(error.new_argument_m_out_of_range_error("M can range from 0 to 65,535.", span)) } + Geometry(Some(srid)) + | Point(Some(srid)) + | LineString(Some(srid)) + | Polygon(Some(srid)) + | MultiPoint(Some(srid)) + | MultiLineString(Some(srid)) + | MultiPolygon(Some(srid)) + | GeometryCollection(Some(srid)) + if *scalar_type == ScalarType::GeoJson && *srid != 4326 => + { + // TODO@geometry MySQL <8 doesn't support SRID parameter, is there a way to catch this here ? + errors.push_error(error.new_argument_m_out_of_range_error("GeoJson SRID must be 4326.", span)) + } Bit(n) if *n > 1 && matches!(scalar_type, ScalarType::Boolean) => { errors.push_error(error.new_argument_m_out_of_range_error("only Bit(1) can be used as Boolean.", span)) } diff --git a/psl/builtin-connectors/src/mysql_datamodel_connector/native_types.rs b/psl/builtin-connectors/src/mysql_datamodel_connector/native_types.rs index 4f17b68dfead..0226658e5568 100644 --- a/psl/builtin-connectors/src/mysql_datamodel_connector/native_types.rs +++ b/psl/builtin-connectors/src/mysql_datamodel_connector/native_types.rs @@ -33,6 +33,14 @@ crate::native_type_definition! { Timestamp(Option) -> DateTime, Year -> Int, Json -> Json, + Geometry(Option) -> Geometry | GeoJson, + Point(Option) -> Geometry | GeoJson, + LineString(Option) -> Geometry | GeoJson, + Polygon(Option) -> Geometry | GeoJson, + MultiPoint(Option) -> Geometry | GeoJson, + MultiLineString(Option) -> Geometry | GeoJson, + MultiPolygon(Option) -> Geometry | GeoJson, + GeometryCollection(Option) -> Geometry | GeoJson, } impl MySqlType { diff --git a/psl/builtin-connectors/src/mysql_datamodel_connector/validations.rs b/psl/builtin-connectors/src/mysql_datamodel_connector/validations.rs index e96ab4ab4078..b4107c6c8a52 100644 --- a/psl/builtin-connectors/src/mysql_datamodel_connector/validations.rs +++ b/psl/builtin-connectors/src/mysql_datamodel_connector/validations.rs @@ -19,6 +19,14 @@ const NATIVE_TYPES_THAT_CAN_NOT_BE_USED_IN_KEY_SPECIFICATION: &[&str] = &[ super::TINY_BLOB_TYPE_NAME, super::MEDIUM_BLOB_TYPE_NAME, super::LONG_BLOB_TYPE_NAME, + super::GEOMETRY_TYPE_NAME, + super::POINT_TYPE_NAME, + super::LINESTRING_TYPE_NAME, + super::POLYGON_TYPE_NAME, + super::MULTIPOINT_TYPE_NAME, + super::MULTILINESTRING_TYPE_NAME, + super::MULTIPOLYGON_TYPE_NAME, + super::GEOMETRYCOLLECTION_TYPE_NAME, ]; pub(crate) fn field_types_can_be_used_in_an_index( diff --git a/psl/builtin-connectors/src/postgres_datamodel_connector.rs b/psl/builtin-connectors/src/postgres_datamodel_connector.rs index 8fac79165c58..6342d633c2d0 100644 --- a/psl/builtin-connectors/src/postgres_datamodel_connector.rs +++ b/psl/builtin-connectors/src/postgres_datamodel_connector.rs @@ -2,6 +2,7 @@ mod datasource; mod native_types; mod validations; +pub use crate::geometry::GeometryParams; pub use native_types::PostgresType; use enumflags2::BitFlags; @@ -18,7 +19,7 @@ use psl_core::{ use std::{borrow::Cow, collections::HashMap}; use PostgresType::*; -use crate::completions; +use crate::{completions, geometry::GeometryType}; const CONSTRAINT_SCOPES: &[ConstraintScope] = &[ ConstraintScope::GlobalPrimaryKeyKeyIndex, @@ -45,6 +46,12 @@ const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(Connector JsonFilteringArrayPath | JsonFilteringAlphanumeric | JsonFilteringAlphanumericFieldRef | + EwktGeometry | + GeoJsonGeometry | + GeometryRawRead | + GeometryFiltering | + GeometryExtraDims | + GeometryExtraTypes | MultiSchema | NamedForeignKeys | NamedPrimaryKeys | @@ -80,6 +87,20 @@ const SCALAR_TYPE_DEFAULTS: &[(ScalarType, PostgresType)] = &[ (ScalarType::DateTime, PostgresType::Timestamp(Some(3))), (ScalarType::Bytes, PostgresType::ByteA), (ScalarType::Json, PostgresType::JsonB), + ( + ScalarType::Geometry, + PostgresType::Geometry(Some(GeometryParams { + ty: GeometryType::Geometry, + srid: 0, + })), + ), + ( + ScalarType::GeoJson, + PostgresType::Geometry(Some(GeometryParams { + ty: GeometryType::Geometry, + srid: 4326, + })), + ), ]; /// Postgres-specific properties in the datasource block. @@ -323,6 +344,9 @@ impl Connector for PostgresDatamodelConnector { JsonB => ScalarType::Json, // Bytes ByteA => ScalarType::Bytes, + // Geometry + Geometry(_) => ScalarType::Geometry, + Geography(_) => ScalarType::Geometry, } } @@ -352,7 +376,7 @@ impl Connector for PostgresDatamodelConnector { fn validate_native_type_arguments( &self, native_type_instance: &NativeTypeInstance, - _scalar_type: &ScalarType, + scalar_type: &ScalarType, span: ast::Span, errors: &mut Diagnostics, ) { @@ -375,6 +399,16 @@ impl Connector for PostgresDatamodelConnector { Timestamp(Some(p)) | Timestamptz(Some(p)) | Time(Some(p)) | Timetz(Some(p)) if *p > 6 => { errors.push_error(error.new_argument_m_out_of_range_error("M can range from 0 to 6.", span)) } + Geometry(Some(g)) | Geography(Some(g)) if *scalar_type == ScalarType::GeoJson && g.ty.is_extra() => errors + .push_error( + error.new_argument_m_out_of_range_error(&format!("{} isn't compatible with GeoJson.", g.ty), span), + ), + Geometry(Some(g)) | Geography(Some(g)) if *scalar_type == ScalarType::GeoJson && g.srid != 4326 => { + errors.push_error(error.new_argument_m_out_of_range_error("GeoJson SRID must be 4326.", span)) + } + Geometry(Some(g)) | Geography(Some(g)) if g.srid < 0 || g.srid > 999000 => { + errors.push_error(error.new_argument_m_out_of_range_error("SRID must be between 0 and 999000.", span)) + } _ => (), } } @@ -567,6 +601,7 @@ impl Connector for PostgresDatamodelConnector { } } +// TODO@geometry: Add index operator classes fn allowed_index_operator_classes(algo: IndexAlgorithm, field: walkers::ScalarFieldWalker<'_>) -> Vec { let scalar_type = field.scalar_type(); let native_type = field.raw_native_type().map(|t| t.1); diff --git a/psl/builtin-connectors/src/postgres_datamodel_connector/native_types.rs b/psl/builtin-connectors/src/postgres_datamodel_connector/native_types.rs index d33f03a22d4f..21bcb5342e48 100644 --- a/psl/builtin-connectors/src/postgres_datamodel_connector/native_types.rs +++ b/psl/builtin-connectors/src/postgres_datamodel_connector/native_types.rs @@ -1,3 +1,5 @@ +use crate::geometry::GeometryParams; + crate::native_type_definition! { PostgresType; SmallInt -> Int, @@ -26,4 +28,6 @@ crate::native_type_definition! { Xml -> String, Json -> Json, JsonB -> Json, + Geometry(Option) -> Geometry | GeoJson, + Geography(Option) -> Geometry | GeoJson, } diff --git a/psl/builtin-connectors/src/sqlite_datamodel_connector.rs b/psl/builtin-connectors/src/sqlite_datamodel_connector.rs index d5e6041f9b43..7c599d5aca12 100644 --- a/psl/builtin-connectors/src/sqlite_datamodel_connector.rs +++ b/psl/builtin-connectors/src/sqlite_datamodel_connector.rs @@ -1,20 +1,29 @@ +mod native_types; +pub use native_types::SQLiteType; + use enumflags2::BitFlags; use psl_core::{ datamodel_connector::{ Connector, ConnectorCapabilities, ConnectorCapability, ConstraintScope, Flavour, NativeTypeConstructor, NativeTypeInstance, }, - diagnostics::{DatamodelError, Diagnostics, Span}, + diagnostics::{Diagnostics, Span}, parser_database::{ReferentialAction, ScalarType}, }; use std::borrow::Cow; -const NATIVE_TYPE_CONSTRUCTORS: &[NativeTypeConstructor] = &[]; +use crate::geometry::{GeometryParams, GeometryType}; + const CONSTRAINT_SCOPES: &[ConstraintScope] = &[ConstraintScope::GlobalKeyIndex]; const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(ConnectorCapability::{ AnyId | AutoIncrement | CompoundIds | + EwktGeometry | + GeoJsonGeometry | + GeometryRawRead | + GeometryFiltering | + GeometryExtraDims | SqlQueryRaw | RelationFieldsInArbitraryOrder | UpdateableId | @@ -31,6 +40,23 @@ const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(Connector // Since we care to stay consistent with reads, it is not enabled. }); +const SCALAR_TYPE_DEFAULTS: &[(ScalarType, SQLiteType)] = &[ + ( + ScalarType::Geometry, + SQLiteType::Geometry(Some(GeometryParams { + ty: GeometryType::Geometry, + srid: 0, + })), + ), + ( + ScalarType::GeoJson, + SQLiteType::Geometry(Some(GeometryParams { + ty: GeometryType::Geometry, + srid: 4326, + })), + ), +]; + pub struct SqliteDatamodelConnector; impl Connector for SqliteDatamodelConnector { @@ -62,24 +88,62 @@ impl Connector for SqliteDatamodelConnector { Restrict | SetNull | Cascade } - fn scalar_type_for_native_type(&self, _native_type: &NativeTypeInstance) -> ScalarType { - unreachable!("No native types on Sqlite"); + fn scalar_type_for_native_type(&self, native_type: &NativeTypeInstance) -> ScalarType { + let native_type: &SQLiteType = native_type.downcast_ref(); + match native_type { + SQLiteType::Geometry(_) => ScalarType::Geometry, + } } - fn default_native_type_for_scalar_type(&self, _scalar_type: &ScalarType) -> NativeTypeInstance { - NativeTypeInstance::new(()) + fn default_native_type_for_scalar_type(&self, scalar_type: &ScalarType) -> NativeTypeInstance { + SCALAR_TYPE_DEFAULTS + .iter() + .find(|(st, _)| st == scalar_type) + .map(|(_, native_type)| native_type) + .map(|nt| NativeTypeInstance::new::(*nt)) + .unwrap_or(NativeTypeInstance::new(())) } fn native_type_is_default_for_scalar_type( &self, - _native_type: &NativeTypeInstance, - _scalar_type: &ScalarType, + native_type: &NativeTypeInstance, + scalar_type: &ScalarType, ) -> bool { - false + let native_type: &SQLiteType = native_type.downcast_ref(); + + SCALAR_TYPE_DEFAULTS + .iter() + .any(|(st, nt)| scalar_type == st && native_type == nt) + } + + fn validate_native_type_arguments( + &self, + native_type_instance: &NativeTypeInstance, + scalar_type: &ScalarType, + span: Span, + errors: &mut Diagnostics, + ) { + let native_type: &SQLiteType = native_type_instance.downcast_ref(); + let error = self.native_instance_error(native_type_instance); + + match native_type { + SQLiteType::Geometry(Some(g)) if *scalar_type == ScalarType::GeoJson && g.srid != 4326 => { + errors.push_error(error.new_argument_m_out_of_range_error("GeoJson SRID must be 4326.", span)) + } + SQLiteType::Geometry(Some(g)) if g.srid < -1 => errors + .push_error(error.new_argument_m_out_of_range_error("SRID must be superior or equal to -1.", span)), + SQLiteType::Geometry(Some(g)) if g.ty.is_extra() => { + errors.push_error(error.new_argument_m_out_of_range_error( + &format!("{} isn't supported for the current connector.", g.ty), + span, + )) + } + _ => (), + } } - fn native_type_to_parts(&self, _native_type: &NativeTypeInstance) -> (&'static str, Vec) { - unreachable!() + fn native_type_to_parts(&self, native_type: &NativeTypeInstance) -> (&'static str, Vec) { + native_type.downcast_ref::().to_parts() } fn constraint_violation_scopes(&self) -> &'static [ConstraintScope] { @@ -87,21 +151,17 @@ impl Connector for SqliteDatamodelConnector { } fn available_native_type_constructors(&self) -> &'static [NativeTypeConstructor] { - NATIVE_TYPE_CONSTRUCTORS + native_types::CONSTRUCTORS } fn parse_native_type( &self, - _name: &str, - _args: &[String], + name: &str, + args: &[String], span: Span, diagnostics: &mut Diagnostics, ) -> Option { - diagnostics.push_error(DatamodelError::new_native_types_not_supported( - self.name().to_owned(), - span, - )); - None + SQLiteType::from_parts(name, args, span, diagnostics).map(NativeTypeInstance::new::) } fn set_config_dir<'a>(&self, config_dir: &std::path::Path, url: &'a str) -> Cow<'a, str> { diff --git a/psl/builtin-connectors/src/sqlite_datamodel_connector/native_types.rs b/psl/builtin-connectors/src/sqlite_datamodel_connector/native_types.rs new file mode 100644 index 000000000000..034c50a40136 --- /dev/null +++ b/psl/builtin-connectors/src/sqlite_datamodel_connector/native_types.rs @@ -0,0 +1,7 @@ +use crate::geometry::GeometryParams; + +crate::native_type_definition! { + /// The SQLite native type enum. + SQLiteType; + Geometry(Option) -> Geometry | GeoJson, +} diff --git a/psl/parser-database/src/attributes/default.rs b/psl/parser-database/src/attributes/default.rs index 74593353bd84..6638d085bdd8 100644 --- a/psl/parser-database/src/attributes/default.rs +++ b/psl/parser-database/src/attributes/default.rs @@ -157,6 +157,8 @@ fn validate_scalar_default_literal( match (scalar_type, value) { (ScalarType::String, ast::Expression::StringValue(_, _)) | (ScalarType::Json, ast::Expression::StringValue(_, _)) + | (ScalarType::Geometry, ast::Expression::StringValue(_, _)) + | (ScalarType::GeoJson, ast::Expression::StringValue(_, _)) | (ScalarType::Bytes, ast::Expression::StringValue(_, _)) | (ScalarType::Int, ast::Expression::NumericValue(_, _)) | (ScalarType::BigInt, ast::Expression::NumericValue(_, _)) diff --git a/psl/parser-database/src/types.rs b/psl/parser-database/src/types.rs index 1668243247bb..c2d35c2e823e 100644 --- a/psl/parser-database/src/types.rs +++ b/psl/parser-database/src/types.rs @@ -255,6 +255,11 @@ impl ScalarFieldType { pub fn is_decimal(self) -> bool { matches!(self, Self::BuiltInScalar(ScalarType::Decimal)) } + + /// True if the field's type is Geometry. + pub fn is_geometry(self) -> bool { + matches!(self, Self::BuiltInScalar(ScalarType::Geometry | ScalarType::GeoJson)) + } } #[derive(Debug, Clone)] @@ -416,9 +421,9 @@ impl IndexAlgorithm { match self { IndexAlgorithm::BTree => true, IndexAlgorithm::Hash => true, - IndexAlgorithm::Gist => r#type.is_string(), - IndexAlgorithm::Gin => r#type.is_json() || field.ast_field().arity.is_list(), - IndexAlgorithm::SpGist => r#type.is_string(), + IndexAlgorithm::Gist => r#type.is_string() || r#type.is_geometry(), + IndexAlgorithm::Gin => r#type.is_json() || r#type.is_geometry() || field.ast_field().arity.is_list(), + IndexAlgorithm::SpGist => r#type.is_string() || r#type.is_geometry(), IndexAlgorithm::Brin => { r#type.is_string() || r#type.is_bytes() @@ -427,6 +432,7 @@ impl IndexAlgorithm { || r#type.is_int() || r#type.is_bigint() || r#type.is_decimal() + || r#type.is_geometry() } } } @@ -1222,6 +1228,7 @@ pub enum OperatorClass { /// - `<= (uuid,uuid)` /// - `>= (uuid,uuid)` UuidMinMaxMultiOps, + // TODO@geometry: Define operator classes } impl OperatorClass { @@ -1400,6 +1407,8 @@ pub enum ScalarType { Json, Bytes, Decimal, + Geometry, + GeoJson, } impl ScalarType { @@ -1415,6 +1424,8 @@ impl ScalarType { ScalarType::Json => "Json", ScalarType::Bytes => "Bytes", ScalarType::Decimal => "Decimal", + ScalarType::Geometry => "Geometry", + ScalarType::GeoJson => "GeoJson", } } @@ -1434,6 +1445,8 @@ impl ScalarType { "Json" => Some(ScalarType::Json), "Bytes" => Some(ScalarType::Bytes), "Decimal" => Some(ScalarType::Decimal), + "GeoJson" => Some(ScalarType::GeoJson), + "Geometry" => Some(ScalarType::Geometry), _ => None, } } diff --git a/psl/psl-core/src/datamodel_connector.rs b/psl/psl-core/src/datamodel_connector.rs index 72671e06688f..9ce11726dfdc 100644 --- a/psl/psl-core/src/datamodel_connector.rs +++ b/psl/psl-core/src/datamodel_connector.rs @@ -308,6 +308,18 @@ pub trait Connector: Send + Sync { self.has_capability(ConnectorCapability::DecimalType) } + fn supports_ewkt_geometry_format(&self) -> bool { + self.has_capability(ConnectorCapability::EwktGeometry) + } + + fn supports_geojson_geometry_format(&self) -> bool { + self.has_capability(ConnectorCapability::GeoJsonGeometry) + } + + fn supports_raw_geometry_read(&self) -> bool { + self.has_capability(ConnectorCapability::GeometryRawRead) + } + fn supported_index_types(&self) -> BitFlags { IndexAlgorithm::BTree.into() } diff --git a/psl/psl-core/src/datamodel_connector/capabilities.rs b/psl/psl-core/src/datamodel_connector/capabilities.rs index 1b3f557e6285..e67a7d700c77 100644 --- a/psl/psl-core/src/datamodel_connector/capabilities.rs +++ b/psl/psl-core/src/datamodel_connector/capabilities.rs @@ -55,6 +55,12 @@ capabilities!( TwoWayEmbeddedManyToManyRelation, ImplicitManyToManyRelation, MultiSchema, + EwktGeometry, + GeoJsonGeometry, + GeometryRawRead, + GeometryFiltering, + GeometryExtraDims, + GeometryExtraTypes, //Start of ME/IE only capabilities AutoIncrementAllowedOnNonId, AutoIncrementMultipleAllowed, diff --git a/psl/psl-core/src/datamodel_connector/empty_connector.rs b/psl/psl-core/src/datamodel_connector/empty_connector.rs index 7ac7879c08f4..93692c64012e 100644 --- a/psl/psl-core/src/datamodel_connector/empty_connector.rs +++ b/psl/psl-core/src/datamodel_connector/empty_connector.rs @@ -25,6 +25,7 @@ impl Connector for EmptyDatamodelConnector { CompoundIds | Enums | Json | + GeoJsonGeometry | ImplicitManyToManyRelation }) } diff --git a/psl/psl-core/src/validate/validation_pipeline/validations/default_value.rs b/psl/psl-core/src/validate/validation_pipeline/validations/default_value.rs index 0ac90e8c65d0..990e28bc8afd 100644 --- a/psl/psl-core/src/validate/validation_pipeline/validations/default_value.rs +++ b/psl/psl-core/src/validate/validation_pipeline/validations/default_value.rs @@ -116,6 +116,8 @@ pub(super) fn validate_default_value( &message, "default", *span, )); } + // TODO@geometry: Add geometry default value validation + (ScalarType::Geometry, ast::Expression::StringValue(_value, _span)) => (), _ => (), } } diff --git a/psl/psl-core/src/validate/validation_pipeline/validations/fields.rs b/psl/psl-core/src/validate/validation_pipeline/validations/fields.rs index bdfb340f5191..8cb760e7a602 100644 --- a/psl/psl-core/src/validate/validation_pipeline/validations/fields.rs +++ b/psl/psl-core/src/validate/validation_pipeline/validations/fields.rs @@ -301,6 +301,38 @@ pub(super) fn validate_scalar_field_connector_specific(field: ScalarFieldWalker< } } + ScalarFieldType::BuiltInScalar(ScalarType::Geometry) => { + if !ctx.connector.supports_ewkt_geometry_format() { + ctx.push_error(DatamodelError::new_field_validation_error( + &format!( + "Field `{}` in {container} `{}` can't be of type Geometry. The current connector does not support the Geometry type.", + field.name(), + field.model().name(), + ), + container, + field.model().name(), + field.name(), + field.ast_field().span(), + )); + } + } + + ScalarFieldType::BuiltInScalar(ScalarType::GeoJson) => { + if !ctx.connector.supports_geojson_geometry_format() { + ctx.push_error(DatamodelError::new_field_validation_error( + &format!( + "Field `{}` in {container} `{}` can't be of type GeoJson. The current connector does not support the GeoJson type.", + field.name(), + field.model().name(), + ), + container, + field.model().name(), + field.name(), + field.ast_field().span(), + )); + } + } + _ => (), } diff --git a/psl/psl/tests/base/base_types.rs b/psl/psl/tests/base/base_types.rs index 59348e9fecd6..aacd4dae4198 100644 --- a/psl/psl/tests/base/base_types.rs +++ b/psl/psl/tests/base/base_types.rs @@ -10,6 +10,7 @@ fn parse_scalar_types() { age Int isPro Boolean averageGrade Float + location GeoJson } "#; @@ -31,6 +32,10 @@ fn parse_scalar_types() { user_model .assert_has_scalar_field("averageGrade") .assert_scalar_type(ScalarType::Float); + + user_model + .assert_has_scalar_field("location") + .assert_scalar_type(ScalarType::GeoJson); } #[test] diff --git a/psl/psl/tests/types/cockroachdb_native_types.rs b/psl/psl/tests/types/cockroachdb_native_types.rs index 4f2b4118dbbd..98e6b4c352d9 100644 --- a/psl/psl/tests/types/cockroachdb_native_types.rs +++ b/psl/psl/tests/types/cockroachdb_native_types.rs @@ -184,8 +184,520 @@ fn cockroach_specific_native_types_are_valid() { timesttzcol DateTime @db.Timestamptz uuidcol String @db.Uuid varbitcol String @db.VarBit(200) + geomcol1 GeoJson @db.Geometry(Geometry, 4326) + geomcol2 GeoJson @db.Geometry(GeometryZ, 4326) + geomcol3 GeoJson @db.Geometry(GeometryM, 4326) + geomcol4 GeoJson @db.Geometry(GeometryZM, 4326) + geomcol5 GeoJson @db.Geometry(Point, 4326) + geomcol6 GeoJson @db.Geometry(PointZ, 4326) + geomcol7 GeoJson @db.Geometry(PointM, 4326) + geomcol8 GeoJson @db.Geometry(PointZM, 4326) + geomcol9 GeoJson @db.Geometry(Point, 4326) + geomcol10 GeoJson @db.Geometry(PointZ, 4326) + geomcol11 GeoJson @db.Geometry(PointM, 4326) + geomcol12 GeoJson @db.Geometry(PointZM, 4326) + geomcol13 GeoJson @db.Geometry(LineString, 4326) + geomcol14 GeoJson @db.Geometry(LineStringZ, 4326) + geomcol15 GeoJson @db.Geometry(LineStringM, 4326) + geomcol16 GeoJson @db.Geometry(LineStringZM, 4326) + geomcol17 GeoJson @db.Geometry(Polygon, 4326) + geomcol18 GeoJson @db.Geometry(PolygonZ, 4326) + geomcol19 GeoJson @db.Geometry(PolygonM, 4326) + geomcol20 GeoJson @db.Geometry(PolygonZM, 4326) + geomcol21 GeoJson @db.Geometry(MultiPoint, 4326) + geomcol22 GeoJson @db.Geometry(MultiPointZ, 4326) + geomcol23 GeoJson @db.Geometry(MultiPointM, 4326) + geomcol24 GeoJson @db.Geometry(MultiPointZM, 4326) + geomcol25 GeoJson @db.Geometry(MultiLineString, 4326) + geomcol26 GeoJson @db.Geometry(MultiLineStringZ, 4326) + geomcol27 GeoJson @db.Geometry(MultiLineStringM, 4326) + geomcol28 GeoJson @db.Geometry(MultiLineStringZM, 4326) + geomcol29 GeoJson @db.Geometry(MultiPolygon, 4326) + geomcol30 GeoJson @db.Geometry(MultiPolygonZ, 4326) + geomcol31 GeoJson @db.Geometry(MultiPolygonM, 4326) + geomcol32 GeoJson @db.Geometry(MultiPolygonZM, 4326) + geomcol33 GeoJson @db.Geometry(GeometryCollection, 4326) + geomcol34 GeoJson @db.Geometry(GeometryCollectionZ, 4326) + geomcol35 GeoJson @db.Geometry(GeometryCollectionM, 4326) + geomcol36 GeoJson @db.Geometry(GeometryCollectionZM, 4326) + geogcol1 GeoJson @db.Geography(Geometry, 4326) + geogcol2 GeoJson @db.Geography(GeometryZ, 4326) + geogcol3 GeoJson @db.Geography(GeometryM, 4326) + geogcol4 GeoJson @db.Geography(GeometryZM, 4326) + geogcol5 GeoJson @db.Geography(Point, 4326) + geogcol6 GeoJson @db.Geography(PointZ, 4326) + geogcol7 GeoJson @db.Geography(PointM, 4326) + geogcol8 GeoJson @db.Geography(PointZM, 4326) + geogcol9 GeoJson @db.Geography(Point, 4326) + geogcol10 GeoJson @db.Geography(PointZ, 4326) + geogcol11 GeoJson @db.Geography(PointM, 4326) + geogcol12 GeoJson @db.Geography(PointZM, 4326) + geogcol13 GeoJson @db.Geography(LineString, 4326) + geogcol14 GeoJson @db.Geography(LineStringZ, 4326) + geogcol15 GeoJson @db.Geography(LineStringM, 4326) + geogcol16 GeoJson @db.Geography(LineStringZM, 4326) + geogcol17 GeoJson @db.Geography(Polygon, 4326) + geogcol18 GeoJson @db.Geography(PolygonZ, 4326) + geogcol19 GeoJson @db.Geography(PolygonM, 4326) + geogcol20 GeoJson @db.Geography(PolygonZM, 4326) + geogcol21 GeoJson @db.Geography(MultiPoint, 4326) + geogcol22 GeoJson @db.Geography(MultiPointZ, 4326) + geogcol23 GeoJson @db.Geography(MultiPointM, 4326) + geogcol24 GeoJson @db.Geography(MultiPointZM, 4326) + geogcol25 GeoJson @db.Geography(MultiLineString, 4326) + geogcol26 GeoJson @db.Geography(MultiLineStringZ, 4326) + geogcol27 GeoJson @db.Geography(MultiLineStringM, 4326) + geogcol28 GeoJson @db.Geography(MultiLineStringZM, 4326) + geogcol29 GeoJson @db.Geography(MultiPolygon, 4326) + geogcol30 GeoJson @db.Geography(MultiPolygonZ, 4326) + geogcol31 GeoJson @db.Geography(MultiPolygonM, 4326) + geogcol32 GeoJson @db.Geography(MultiPolygonZM, 4326) + geogcol33 GeoJson @db.Geography(GeometryCollection, 4326) + geogcol34 GeoJson @db.Geography(GeometryCollectionZ, 4326) + geogcol35 GeoJson @db.Geography(GeometryCollectionM, 4326) + geogcol36 GeoJson @db.Geography(GeometryCollectionZM, 4326) } "#}; psl::parse_schema(schema).unwrap(); } + +#[test] +fn should_fail_on_geojson_when_invalid_geometry_type() { + let dml = indoc! {r#" + datasource db { + provider = "cockroachdb" + url = env("DATABASE_URL") + } + + model Blog { + id Int @id + geom GeoJson @db.Geometry(Invalid) + } + "#}; + + let expectation = expect![[r#" + error: Expected a geometry type and an optional srid, but found (Invalid). + --> schema.prisma:8 +  |  +  7 |  id Int @id +  8 |  geom GeoJson @db.Geometry(Invalid) +  |  + "#]]; + + expect_error(dml, &expectation); +} + +#[test] +fn should_fail_on_geojson_when_non_wgs84_srid() { + let schema = indoc! {r#" + datasource db { + provider = "cockroachdb" + url = env("DATABASE_URL") + } + + model User { + id Int @id + geom GeoJson @db.Geometry(Point, 3857) + } + "#}; + + let expectation = expect![[r#" + error: Argument M is out of range for native type `Geometry(Point,3857)` of CockroachDB: GeoJson SRID must be 4326. + --> schema.prisma:8 +  |  +  7 |  id Int @id +  8 |  geom GeoJson @db.Geometry(Point, 3857) +  |  + "#]]; + + expect_error(schema, &expectation); +} + +#[test] +fn should_fail_on_geometry_when_out_of_bound_srid() { + let schema = indoc! {r#" + datasource db { + provider = "cockroachdb" + url = env("DATABASE_URL") + } + + model User { + id Int @id + geom1 Geometry @db.Geometry(Point, -1) + geom2 Geometry @db.Geometry(Point, 1000000) + } + "#}; + + let expectation = expect![[r#" + error: Argument M is out of range for native type `Geometry(Point,-1)` of CockroachDB: SRID must be between 0 and 999000. + --> schema.prisma:8 +  |  +  7 |  id Int @id +  8 |  geom1 Geometry @db.Geometry(Point, -1) +  |  + error: Argument M is out of range for native type `Geometry(Point,1000000)` of CockroachDB: SRID must be between 0 and 999000. + --> schema.prisma:9 +  |  +  8 |  geom1 Geometry @db.Geometry(Point, -1) +  9 |  geom2 Geometry @db.Geometry(Point, 1000000) +  |  + "#]]; + + expect_error(schema, &expectation); +} + +#[test] +fn should_fail_on_geometry_when_extra_geometry_type() { + let schema = indoc! {r#" + datasource db { + provider = "cockroachdb" + url = env("DATABASE_URL") + } + + model User { + id Int @id + geom_00 Geometry @db.Geometry(CircularString, 4326) + geom_01 Geometry @db.Geometry(CircularStringZ, 4326) + geom_02 Geometry @db.Geometry(CircularStringM, 4326) + geom_03 Geometry @db.Geometry(CircularStringZM, 4326) + geom_04 Geometry @db.Geometry(CompoundCurve, 4326) + geom_05 Geometry @db.Geometry(CompoundCurveZ, 4326) + geom_06 Geometry @db.Geometry(CompoundCurveM, 4326) + geom_07 Geometry @db.Geometry(CompoundCurveZM, 4326) + geom_08 Geometry @db.Geometry(CurvePolygon, 4326) + geom_09 Geometry @db.Geometry(CurvePolygonZ, 4326) + geom_10 Geometry @db.Geometry(CurvePolygonM, 4326) + geom_11 Geometry @db.Geometry(CurvePolygonZM, 4326) + geom_12 Geometry @db.Geometry(MultiCurve, 4326) + geom_13 Geometry @db.Geometry(MultiCurveZ, 4326) + geom_14 Geometry @db.Geometry(MultiCurveM, 4326) + geom_15 Geometry @db.Geometry(MultiCurveZM, 4326) + geom_16 Geometry @db.Geometry(MultiSurface, 4326) + geom_17 Geometry @db.Geometry(MultiSurfaceZ, 4326) + geom_18 Geometry @db.Geometry(MultiSurfaceM, 4326) + geom_19 Geometry @db.Geometry(MultiSurfaceZM, 4326) + geom_20 Geometry @db.Geometry(PolyhedralSurface, 4326) + geom_21 Geometry @db.Geometry(PolyhedralSurfaceZ, 4326) + geom_22 Geometry @db.Geometry(PolyhedralSurfaceM, 4326) + geom_23 Geometry @db.Geometry(PolyhedralSurfaceZM, 4326) + geog_00 Geometry @db.Geography(CircularString, 4326) + geog_01 Geometry @db.Geography(CircularStringZ, 4326) + geog_02 Geometry @db.Geography(CircularStringM, 4326) + geog_03 Geometry @db.Geography(CircularStringZM, 4326) + geog_04 Geometry @db.Geography(CompoundCurve, 4326) + geog_05 Geometry @db.Geography(CompoundCurveZ, 4326) + geog_06 Geometry @db.Geography(CompoundCurveM, 4326) + geog_07 Geometry @db.Geography(CompoundCurveZM, 4326) + geog_08 Geometry @db.Geography(CurvePolygon, 4326) + geog_09 Geometry @db.Geography(CurvePolygonZ, 4326) + geog_10 Geometry @db.Geography(CurvePolygonM, 4326) + geog_11 Geometry @db.Geography(CurvePolygonZM, 4326) + geog_12 Geometry @db.Geography(MultiCurve, 4326) + geog_13 Geometry @db.Geography(MultiCurveZ, 4326) + geog_14 Geometry @db.Geography(MultiCurveM, 4326) + geog_15 Geometry @db.Geography(MultiCurveZM, 4326) + geog_16 Geometry @db.Geography(MultiSurface, 4326) + geog_17 Geometry @db.Geography(MultiSurfaceZ, 4326) + geog_18 Geometry @db.Geography(MultiSurfaceM, 4326) + geog_19 Geometry @db.Geography(MultiSurfaceZM, 4326) + geog_20 Geometry @db.Geography(PolyhedralSurface, 4326) + geog_21 Geometry @db.Geography(PolyhedralSurfaceZ, 4326) + geog_22 Geometry @db.Geography(PolyhedralSurfaceM, 4326) + geog_23 Geometry @db.Geography(PolyhedralSurfaceZM, 4326) + } + "#}; + + let expectation = expect![[r#" + error: Argument M is out of range for native type `Geometry(CircularString,4326)` of CockroachDB: CircularString isn't supported for the current connector. + --> schema.prisma:8 +  |  +  7 |  id Int @id +  8 |  geom_00 Geometry @db.Geometry(CircularString, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CircularStringZ,4326)` of CockroachDB: CircularStringZ isn't supported for the current connector. + --> schema.prisma:9 +  |  +  8 |  geom_00 Geometry @db.Geometry(CircularString, 4326) +  9 |  geom_01 Geometry @db.Geometry(CircularStringZ, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CircularStringM,4326)` of CockroachDB: CircularStringM isn't supported for the current connector. + --> schema.prisma:10 +  |  +  9 |  geom_01 Geometry @db.Geometry(CircularStringZ, 4326) + 10 |  geom_02 Geometry @db.Geometry(CircularStringM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CircularStringZM,4326)` of CockroachDB: CircularStringZM isn't supported for the current connector. + --> schema.prisma:11 +  |  + 10 |  geom_02 Geometry @db.Geometry(CircularStringM, 4326) + 11 |  geom_03 Geometry @db.Geometry(CircularStringZM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CompoundCurve,4326)` of CockroachDB: CompoundCurve isn't supported for the current connector. + --> schema.prisma:12 +  |  + 11 |  geom_03 Geometry @db.Geometry(CircularStringZM, 4326) + 12 |  geom_04 Geometry @db.Geometry(CompoundCurve, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CompoundCurveZ,4326)` of CockroachDB: CompoundCurveZ isn't supported for the current connector. + --> schema.prisma:13 +  |  + 12 |  geom_04 Geometry @db.Geometry(CompoundCurve, 4326) + 13 |  geom_05 Geometry @db.Geometry(CompoundCurveZ, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CompoundCurveM,4326)` of CockroachDB: CompoundCurveM isn't supported for the current connector. + --> schema.prisma:14 +  |  + 13 |  geom_05 Geometry @db.Geometry(CompoundCurveZ, 4326) + 14 |  geom_06 Geometry @db.Geometry(CompoundCurveM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CompoundCurveZM,4326)` of CockroachDB: CompoundCurveZM isn't supported for the current connector. + --> schema.prisma:15 +  |  + 14 |  geom_06 Geometry @db.Geometry(CompoundCurveM, 4326) + 15 |  geom_07 Geometry @db.Geometry(CompoundCurveZM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CurvePolygon,4326)` of CockroachDB: CurvePolygon isn't supported for the current connector. + --> schema.prisma:16 +  |  + 15 |  geom_07 Geometry @db.Geometry(CompoundCurveZM, 4326) + 16 |  geom_08 Geometry @db.Geometry(CurvePolygon, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CurvePolygonZ,4326)` of CockroachDB: CurvePolygonZ isn't supported for the current connector. + --> schema.prisma:17 +  |  + 16 |  geom_08 Geometry @db.Geometry(CurvePolygon, 4326) + 17 |  geom_09 Geometry @db.Geometry(CurvePolygonZ, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CurvePolygonM,4326)` of CockroachDB: CurvePolygonM isn't supported for the current connector. + --> schema.prisma:18 +  |  + 17 |  geom_09 Geometry @db.Geometry(CurvePolygonZ, 4326) + 18 |  geom_10 Geometry @db.Geometry(CurvePolygonM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CurvePolygonZM,4326)` of CockroachDB: CurvePolygonZM isn't supported for the current connector. + --> schema.prisma:19 +  |  + 18 |  geom_10 Geometry @db.Geometry(CurvePolygonM, 4326) + 19 |  geom_11 Geometry @db.Geometry(CurvePolygonZM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiCurve,4326)` of CockroachDB: MultiCurve isn't supported for the current connector. + --> schema.prisma:20 +  |  + 19 |  geom_11 Geometry @db.Geometry(CurvePolygonZM, 4326) + 20 |  geom_12 Geometry @db.Geometry(MultiCurve, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiCurveZ,4326)` of CockroachDB: MultiCurveZ isn't supported for the current connector. + --> schema.prisma:21 +  |  + 20 |  geom_12 Geometry @db.Geometry(MultiCurve, 4326) + 21 |  geom_13 Geometry @db.Geometry(MultiCurveZ, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiCurveM,4326)` of CockroachDB: MultiCurveM isn't supported for the current connector. + --> schema.prisma:22 +  |  + 21 |  geom_13 Geometry @db.Geometry(MultiCurveZ, 4326) + 22 |  geom_14 Geometry @db.Geometry(MultiCurveM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiCurveZM,4326)` of CockroachDB: MultiCurveZM isn't supported for the current connector. + --> schema.prisma:23 +  |  + 22 |  geom_14 Geometry @db.Geometry(MultiCurveM, 4326) + 23 |  geom_15 Geometry @db.Geometry(MultiCurveZM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiSurface,4326)` of CockroachDB: MultiSurface isn't supported for the current connector. + --> schema.prisma:24 +  |  + 23 |  geom_15 Geometry @db.Geometry(MultiCurveZM, 4326) + 24 |  geom_16 Geometry @db.Geometry(MultiSurface, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiSurfaceZ,4326)` of CockroachDB: MultiSurfaceZ isn't supported for the current connector. + --> schema.prisma:25 +  |  + 24 |  geom_16 Geometry @db.Geometry(MultiSurface, 4326) + 25 |  geom_17 Geometry @db.Geometry(MultiSurfaceZ, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiSurfaceM,4326)` of CockroachDB: MultiSurfaceM isn't supported for the current connector. + --> schema.prisma:26 +  |  + 25 |  geom_17 Geometry @db.Geometry(MultiSurfaceZ, 4326) + 26 |  geom_18 Geometry @db.Geometry(MultiSurfaceM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiSurfaceZM,4326)` of CockroachDB: MultiSurfaceZM isn't supported for the current connector. + --> schema.prisma:27 +  |  + 26 |  geom_18 Geometry @db.Geometry(MultiSurfaceM, 4326) + 27 |  geom_19 Geometry @db.Geometry(MultiSurfaceZM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(PolyhedralSurface,4326)` of CockroachDB: PolyhedralSurface isn't supported for the current connector. + --> schema.prisma:28 +  |  + 27 |  geom_19 Geometry @db.Geometry(MultiSurfaceZM, 4326) + 28 |  geom_20 Geometry @db.Geometry(PolyhedralSurface, 4326) +  |  + error: Argument M is out of range for native type `Geometry(PolyhedralSurfaceZ,4326)` of CockroachDB: PolyhedralSurfaceZ isn't supported for the current connector. + --> schema.prisma:29 +  |  + 28 |  geom_20 Geometry @db.Geometry(PolyhedralSurface, 4326) + 29 |  geom_21 Geometry @db.Geometry(PolyhedralSurfaceZ, 4326) +  |  + error: Argument M is out of range for native type `Geometry(PolyhedralSurfaceM,4326)` of CockroachDB: PolyhedralSurfaceM isn't supported for the current connector. + --> schema.prisma:30 +  |  + 29 |  geom_21 Geometry @db.Geometry(PolyhedralSurfaceZ, 4326) + 30 |  geom_22 Geometry @db.Geometry(PolyhedralSurfaceM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(PolyhedralSurfaceZM,4326)` of CockroachDB: PolyhedralSurfaceZM isn't supported for the current connector. + --> schema.prisma:31 +  |  + 30 |  geom_22 Geometry @db.Geometry(PolyhedralSurfaceM, 4326) + 31 |  geom_23 Geometry @db.Geometry(PolyhedralSurfaceZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(CircularString,4326)` of CockroachDB: CircularString isn't supported for the current connector. + --> schema.prisma:32 +  |  + 31 |  geom_23 Geometry @db.Geometry(PolyhedralSurfaceZM, 4326) + 32 |  geog_00 Geometry @db.Geography(CircularString, 4326) +  |  + error: Argument M is out of range for native type `Geography(CircularStringZ,4326)` of CockroachDB: CircularStringZ isn't supported for the current connector. + --> schema.prisma:33 +  |  + 32 |  geog_00 Geometry @db.Geography(CircularString, 4326) + 33 |  geog_01 Geometry @db.Geography(CircularStringZ, 4326) +  |  + error: Argument M is out of range for native type `Geography(CircularStringM,4326)` of CockroachDB: CircularStringM isn't supported for the current connector. + --> schema.prisma:34 +  |  + 33 |  geog_01 Geometry @db.Geography(CircularStringZ, 4326) + 34 |  geog_02 Geometry @db.Geography(CircularStringM, 4326) +  |  + error: Argument M is out of range for native type `Geography(CircularStringZM,4326)` of CockroachDB: CircularStringZM isn't supported for the current connector. + --> schema.prisma:35 +  |  + 34 |  geog_02 Geometry @db.Geography(CircularStringM, 4326) + 35 |  geog_03 Geometry @db.Geography(CircularStringZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(CompoundCurve,4326)` of CockroachDB: CompoundCurve isn't supported for the current connector. + --> schema.prisma:36 +  |  + 35 |  geog_03 Geometry @db.Geography(CircularStringZM, 4326) + 36 |  geog_04 Geometry @db.Geography(CompoundCurve, 4326) +  |  + error: Argument M is out of range for native type `Geography(CompoundCurveZ,4326)` of CockroachDB: CompoundCurveZ isn't supported for the current connector. + --> schema.prisma:37 +  |  + 36 |  geog_04 Geometry @db.Geography(CompoundCurve, 4326) + 37 |  geog_05 Geometry @db.Geography(CompoundCurveZ, 4326) +  |  + error: Argument M is out of range for native type `Geography(CompoundCurveM,4326)` of CockroachDB: CompoundCurveM isn't supported for the current connector. + --> schema.prisma:38 +  |  + 37 |  geog_05 Geometry @db.Geography(CompoundCurveZ, 4326) + 38 |  geog_06 Geometry @db.Geography(CompoundCurveM, 4326) +  |  + error: Argument M is out of range for native type `Geography(CompoundCurveZM,4326)` of CockroachDB: CompoundCurveZM isn't supported for the current connector. + --> schema.prisma:39 +  |  + 38 |  geog_06 Geometry @db.Geography(CompoundCurveM, 4326) + 39 |  geog_07 Geometry @db.Geography(CompoundCurveZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(CurvePolygon,4326)` of CockroachDB: CurvePolygon isn't supported for the current connector. + --> schema.prisma:40 +  |  + 39 |  geog_07 Geometry @db.Geography(CompoundCurveZM, 4326) + 40 |  geog_08 Geometry @db.Geography(CurvePolygon, 4326) +  |  + error: Argument M is out of range for native type `Geography(CurvePolygonZ,4326)` of CockroachDB: CurvePolygonZ isn't supported for the current connector. + --> schema.prisma:41 +  |  + 40 |  geog_08 Geometry @db.Geography(CurvePolygon, 4326) + 41 |  geog_09 Geometry @db.Geography(CurvePolygonZ, 4326) +  |  + error: Argument M is out of range for native type `Geography(CurvePolygonM,4326)` of CockroachDB: CurvePolygonM isn't supported for the current connector. + --> schema.prisma:42 +  |  + 41 |  geog_09 Geometry @db.Geography(CurvePolygonZ, 4326) + 42 |  geog_10 Geometry @db.Geography(CurvePolygonM, 4326) +  |  + error: Argument M is out of range for native type `Geography(CurvePolygonZM,4326)` of CockroachDB: CurvePolygonZM isn't supported for the current connector. + --> schema.prisma:43 +  |  + 42 |  geog_10 Geometry @db.Geography(CurvePolygonM, 4326) + 43 |  geog_11 Geometry @db.Geography(CurvePolygonZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiCurve,4326)` of CockroachDB: MultiCurve isn't supported for the current connector. + --> schema.prisma:44 +  |  + 43 |  geog_11 Geometry @db.Geography(CurvePolygonZM, 4326) + 44 |  geog_12 Geometry @db.Geography(MultiCurve, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiCurveZ,4326)` of CockroachDB: MultiCurveZ isn't supported for the current connector. + --> schema.prisma:45 +  |  + 44 |  geog_12 Geometry @db.Geography(MultiCurve, 4326) + 45 |  geog_13 Geometry @db.Geography(MultiCurveZ, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiCurveM,4326)` of CockroachDB: MultiCurveM isn't supported for the current connector. + --> schema.prisma:46 +  |  + 45 |  geog_13 Geometry @db.Geography(MultiCurveZ, 4326) + 46 |  geog_14 Geometry @db.Geography(MultiCurveM, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiCurveZM,4326)` of CockroachDB: MultiCurveZM isn't supported for the current connector. + --> schema.prisma:47 +  |  + 46 |  geog_14 Geometry @db.Geography(MultiCurveM, 4326) + 47 |  geog_15 Geometry @db.Geography(MultiCurveZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiSurface,4326)` of CockroachDB: MultiSurface isn't supported for the current connector. + --> schema.prisma:48 +  |  + 47 |  geog_15 Geometry @db.Geography(MultiCurveZM, 4326) + 48 |  geog_16 Geometry @db.Geography(MultiSurface, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiSurfaceZ,4326)` of CockroachDB: MultiSurfaceZ isn't supported for the current connector. + --> schema.prisma:49 +  |  + 48 |  geog_16 Geometry @db.Geography(MultiSurface, 4326) + 49 |  geog_17 Geometry @db.Geography(MultiSurfaceZ, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiSurfaceM,4326)` of CockroachDB: MultiSurfaceM isn't supported for the current connector. + --> schema.prisma:50 +  |  + 49 |  geog_17 Geometry @db.Geography(MultiSurfaceZ, 4326) + 50 |  geog_18 Geometry @db.Geography(MultiSurfaceM, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiSurfaceZM,4326)` of CockroachDB: MultiSurfaceZM isn't supported for the current connector. + --> schema.prisma:51 +  |  + 50 |  geog_18 Geometry @db.Geography(MultiSurfaceM, 4326) + 51 |  geog_19 Geometry @db.Geography(MultiSurfaceZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(PolyhedralSurface,4326)` of CockroachDB: PolyhedralSurface isn't supported for the current connector. + --> schema.prisma:52 +  |  + 51 |  geog_19 Geometry @db.Geography(MultiSurfaceZM, 4326) + 52 |  geog_20 Geometry @db.Geography(PolyhedralSurface, 4326) +  |  + error: Argument M is out of range for native type `Geography(PolyhedralSurfaceZ,4326)` of CockroachDB: PolyhedralSurfaceZ isn't supported for the current connector. + --> schema.prisma:53 +  |  + 52 |  geog_20 Geometry @db.Geography(PolyhedralSurface, 4326) + 53 |  geog_21 Geometry @db.Geography(PolyhedralSurfaceZ, 4326) +  |  + error: Argument M is out of range for native type `Geography(PolyhedralSurfaceM,4326)` of CockroachDB: PolyhedralSurfaceM isn't supported for the current connector. + --> schema.prisma:54 +  |  + 53 |  geog_21 Geometry @db.Geography(PolyhedralSurfaceZ, 4326) + 54 |  geog_22 Geometry @db.Geography(PolyhedralSurfaceM, 4326) +  |  + error: Argument M is out of range for native type `Geography(PolyhedralSurfaceZM,4326)` of CockroachDB: PolyhedralSurfaceZM isn't supported for the current connector. + --> schema.prisma:55 +  |  + 54 |  geog_22 Geometry @db.Geography(PolyhedralSurfaceM, 4326) + 55 |  geog_23 Geometry @db.Geography(PolyhedralSurfaceZM, 4326) +  |  + "#]]; + + expect_error(schema, &expectation); +} diff --git a/psl/psl/tests/types/mod.rs b/psl/psl/tests/types/mod.rs index 91d64a22db89..8759552a0aa5 100644 --- a/psl/psl/tests/types/mod.rs +++ b/psl/psl/tests/types/mod.rs @@ -6,3 +6,4 @@ mod mysql_native_types; mod negative; mod positive; mod postgres_native_types; +mod sqlite_native_types; diff --git a/psl/psl/tests/types/mssql_native_types.rs b/psl/psl/tests/types/mssql_native_types.rs index 44b2f36f5e31..e85ede859506 100644 --- a/psl/psl/tests/types/mssql_native_types.rs +++ b/psl/psl/tests/types/mssql_native_types.rs @@ -204,6 +204,64 @@ fn image_type_should_fail_on_unique() { expect_error(schema, &expectation); } +#[test] +fn geometry_type_should_fail_on_unique() { + let schema = indoc! {r#" + datasource db { + provider = "sqlserver" + url = env("DATABASE_URL") + } + + model User { + id Int @id + geom GeoJson @db.Geometry + geog GeoJson @db.Geometry + + @@unique([geom, geog]) + } + "#}; + + let expectation = expect![[r#" + error: Native type `Geometry` cannot be unique in SQL Server. + --> schema.prisma:11 +  |  + 10 |  + 11 |  @@unique([geom, geog]) +  |  + "#]]; + + expect_error(schema, &expectation); +} + +#[test] +fn geography_type_should_fail_on_unique() { + let schema = indoc! {r#" + datasource db { + provider = "sqlserver" + url = env("DATABASE_URL") + } + + model User { + id Int @id + geom GeoJson @db.Geography + geog GeoJson @db.Geography + + @@unique([geom, geog]) + } + "#}; + + let expectation = expect![[r#" + error: Native type `Geography` cannot be unique in SQL Server. + --> schema.prisma:11 +  |  + 10 |  + 11 |  @@unique([geom, geog]) +  |  + "#]]; + + expect_error(schema, &expectation); +} + #[test] fn text_type_should_fail_on_index() { let schema = indoc! {r#" @@ -407,6 +465,64 @@ fn image_type_should_fail_on_index() { expect_error(schema, &expectation); } +#[test] +fn geometry_type_should_fail_on_index() { + let schema = indoc! {r#" + datasource db { + provider = "sqlserver" + url = env("DATABASE_URL") + } + + model User { + id Int @id + firstName GeoJson @db.Geometry + lastName GeoJson @db.Geometry + + @@index([firstName, lastName]) + } + "#}; + + let expectation = expect![[r#" + error: You cannot define an index on fields with native type `Geometry` of SQL Server. + --> schema.prisma:11 +  |  + 10 |  + 11 |  @@index([firstName, lastName]) +  |  + "#]]; + + expect_error(schema, &expectation); +} + +#[test] +fn geography_type_should_fail_on_index() { + let schema = indoc! {r#" + datasource db { + provider = "sqlserver" + url = env("DATABASE_URL") + } + + model User { + id Int @id + firstName GeoJson @db.Geography + lastName GeoJson @db.Geography + + @@index([firstName, lastName]) + } + "#}; + + let expectation = expect![[r#" + error: You cannot define an index on fields with native type `Geography` of SQL Server. + --> schema.prisma:11 +  |  + 10 |  + 11 |  @@index([firstName, lastName]) +  |  + "#]]; + + expect_error(schema, &expectation); +} + #[test] fn text_type_should_fail_on_id() { let schema = indoc! {r#" @@ -603,6 +719,62 @@ fn image_type_should_fail_on_id() { expect_error(schema, &expectation); } +#[test] +fn geometry_type_should_fail_on_id() { + let schema = indoc! {r#" + datasource db { + provider = "sqlserver" + url = env("DATABASE_URL") + } + + model User { + firstName GeoJson @db.Geometry + lastName GeoJson @db.Geometry + + @@id([firstName, lastName]) + } + "#}; + + let expectation = expect![[r#" + error: Native type `Geometry` of SQL Server cannot be used on a field that is `@id` or `@@id`. + --> schema.prisma:10 +  |  +  9 |  + 10 |  @@id([firstName, lastName]) +  |  + "#]]; + + expect_error(schema, &expectation); +} + +#[test] +fn geography_type_should_fail_on_id() { + let schema = indoc! {r#" + datasource db { + provider = "sqlserver" + url = env("DATABASE_URL") + } + + model User { + firstName GeoJson @db.Geography + lastName GeoJson @db.Geography + + @@id([firstName, lastName]) + } + "#}; + + let expectation = expect![[r#" + error: Native type `Geography` of SQL Server cannot be used on a field that is `@id` or `@@id`. + --> schema.prisma:10 +  |  +  9 |  + 10 |  @@id([firstName, lastName]) +  |  + "#]]; + + expect_error(schema, &expectation); +} + #[test] fn should_fail_on_native_type_decimal_when_scale_is_bigger_than_precision() { let schema = indoc! {r#" @@ -910,6 +1082,10 @@ mod test_type_mapping { test_type!(ntext(("String @db.NText", MsSqlType::NText))); test_type!(image(("Bytes @db.Image", MsSqlType::Image))); test_type!(xml(("String @db.Xml", MsSqlType::Xml))); + test_type!(geojsongeometry(("GeoJson @db.Geometry", MsSqlType::Geometry))); + test_type!(geojsongeography(("GeoJson @db.Geography", MsSqlType::Geography))); + test_type!(ewktgeometry(("Geometry @db.Geometry", MsSqlType::Geometry))); + test_type!(ewktgeography(("Geometry @db.Geography", MsSqlType::Geography))); test_type!(datetimeoffset(( "DateTime @db.DateTimeOffset", diff --git a/psl/psl/tests/types/mysql_native_types.rs b/psl/psl/tests/types/mysql_native_types.rs index 2aeea1808718..2c15b4c7f499 100644 --- a/psl/psl/tests/types/mysql_native_types.rs +++ b/psl/psl/tests/types/mysql_native_types.rs @@ -464,6 +464,238 @@ fn tinyblob_type_should_fail_on_index() { expect_error(schema, &expectation); } +#[test] +fn geometry_type_should_fail_on_index() { + let schema = indoc! {r#" + datasource db { + provider = "mysql" + url = env("DATABASE_URL") + } + + model User { + id Int @id + firstName GeoJson @db.Geometry + lastName GeoJson @db.Geometry + + @@index([firstName, lastName]) + } + "#}; + + let expectation = expect![[r#" + error: You cannot define an index on fields with native type `Geometry` of MySQL. Please use the `length` argument to the field in the index definition to allow this. + --> schema.prisma:11 +  |  + 10 |  + 11 |  @@index([firstName, lastName]) +  |  + "#]]; + + expect_error(schema, &expectation); +} + +#[test] +fn point_type_should_fail_on_index() { + let schema = indoc! {r#" + datasource db { + provider = "mysql" + url = env("DATABASE_URL") + } + + model User { + id Int @id + firstName GeoJson @db.Point + lastName GeoJson @db.Point + + @@index([firstName, lastName]) + } + "#}; + + let expectation = expect![[r#" + error: You cannot define an index on fields with native type `Point` of MySQL. Please use the `length` argument to the field in the index definition to allow this. + --> schema.prisma:11 +  |  + 10 |  + 11 |  @@index([firstName, lastName]) +  |  + "#]]; + + expect_error(schema, &expectation); +} + +#[test] +fn linestring_type_should_fail_on_index() { + let schema = indoc! {r#" + datasource db { + provider = "mysql" + url = env("DATABASE_URL") + } + + model User { + id Int @id + firstName GeoJson @db.LineString + lastName GeoJson @db.LineString + + @@index([firstName, lastName]) + } + "#}; + + let expectation = expect![[r#" + error: You cannot define an index on fields with native type `LineString` of MySQL. Please use the `length` argument to the field in the index definition to allow this. + --> schema.prisma:11 +  |  + 10 |  + 11 |  @@index([firstName, lastName]) +  |  + "#]]; + + expect_error(schema, &expectation); +} + +#[test] +fn polygon_type_should_fail_on_index() { + let schema = indoc! {r#" + datasource db { + provider = "mysql" + url = env("DATABASE_URL") + } + + model User { + id Int @id + firstName GeoJson @db.Polygon + lastName GeoJson @db.Polygon + + @@index([firstName, lastName]) + } + "#}; + + let expectation = expect![[r#" + error: You cannot define an index on fields with native type `Polygon` of MySQL. Please use the `length` argument to the field in the index definition to allow this. + --> schema.prisma:11 +  |  + 10 |  + 11 |  @@index([firstName, lastName]) +  |  + "#]]; + + expect_error(schema, &expectation); +} + +#[test] +fn multipoint_type_should_fail_on_index() { + let schema = indoc! {r#" + datasource db { + provider = "mysql" + url = env("DATABASE_URL") + } + + model User { + id Int @id + firstName GeoJson @db.MultiPoint + lastName GeoJson @db.MultiPoint + + @@index([firstName, lastName]) + } + "#}; + + let expectation = expect![[r#" + error: You cannot define an index on fields with native type `MultiPoint` of MySQL. Please use the `length` argument to the field in the index definition to allow this. + --> schema.prisma:11 +  |  + 10 |  + 11 |  @@index([firstName, lastName]) +  |  + "#]]; + + expect_error(schema, &expectation); +} + +#[test] +fn multilinestring_type_should_fail_on_index() { + let schema = indoc! {r#" + datasource db { + provider = "mysql" + url = env("DATABASE_URL") + } + + model User { + id Int @id + firstName GeoJson @db.MultiLineString + lastName GeoJson @db.MultiLineString + + @@index([firstName, lastName]) + } + "#}; + + let expectation = expect![[r#" + error: You cannot define an index on fields with native type `MultiLineString` of MySQL. Please use the `length` argument to the field in the index definition to allow this. + --> schema.prisma:11 +  |  + 10 |  + 11 |  @@index([firstName, lastName]) +  |  + "#]]; + + expect_error(schema, &expectation); +} + +#[test] +fn multipolygon_type_should_fail_on_index() { + let schema = indoc! {r#" + datasource db { + provider = "mysql" + url = env("DATABASE_URL") + } + + model User { + id Int @id + firstName GeoJson @db.MultiPolygon + lastName GeoJson @db.MultiPolygon + + @@index([firstName, lastName]) + } + "#}; + + let expectation = expect![[r#" + error: You cannot define an index on fields with native type `MultiPolygon` of MySQL. Please use the `length` argument to the field in the index definition to allow this. + --> schema.prisma:11 +  |  + 10 |  + 11 |  @@index([firstName, lastName]) +  |  + "#]]; + + expect_error(schema, &expectation); +} + +#[test] +fn geometrycollection_type_should_fail_on_index() { + let schema = indoc! {r#" + datasource db { + provider = "mysql" + url = env("DATABASE_URL") + } + + model User { + id Int @id + firstName GeoJson @db.GeometryCollection + lastName GeoJson @db.GeometryCollection + + @@index([firstName, lastName]) + } + "#}; + + let expectation = expect![[r#" + error: You cannot define an index on fields with native type `GeometryCollection` of MySQL. Please use the `length` argument to the field in the index definition to allow this. + --> schema.prisma:11 +  |  + 10 |  + 11 |  @@index([firstName, lastName]) +  |  + "#]]; + + expect_error(schema, &expectation); +} + #[test] fn text_type_should_fail_on_id() { let schema = indoc! {r#" @@ -688,6 +920,305 @@ fn tinyblob_type_should_fail_on_id() { expect_error(schema, &expectation); } +#[test] +fn geometry_type_should_fail_on_id() { + let schema = indoc! {r#" + datasource db { + provider = "mysql" + url = env("DATABASE_URL") + } + + model User { + firstName GeoJson @db.Geometry + lastName GeoJson @db.Geometry + + @@id([firstName, lastName]) + } + "#}; + + let expectation = expect![[r#" + error: Native type `Geometry` of MySQL cannot be used on a field that is `@id` or `@@id`. Please use the `length` argument to the field in the index definition to allow this. + --> schema.prisma:10 +  |  +  9 |  + 10 |  @@id([firstName, lastName]) +  |  + "#]]; + + expect_error(schema, &expectation); +} + +#[test] +fn point_type_should_fail_on_id() { + let schema = indoc! {r#" + datasource db { + provider = "mysql" + url = env("DATABASE_URL") + } + + model User { + firstName GeoJson @db.Point + lastName GeoJson @db.Point + + @@id([firstName, lastName]) + } + "#}; + + let expectation = expect![[r#" + error: Native type `Point` of MySQL cannot be used on a field that is `@id` or `@@id`. Please use the `length` argument to the field in the index definition to allow this. + --> schema.prisma:10 +  |  +  9 |  + 10 |  @@id([firstName, lastName]) +  |  + "#]]; + + expect_error(schema, &expectation); +} + +#[test] +fn linestring_type_should_fail_on_id() { + let schema = indoc! {r#" + datasource db { + provider = "mysql" + url = env("DATABASE_URL") + } + + model User { + firstName GeoJson @db.LineString + lastName GeoJson @db.LineString + + @@id([firstName, lastName]) + } + "#}; + + let expectation = expect![[r#" + error: Native type `LineString` of MySQL cannot be used on a field that is `@id` or `@@id`. Please use the `length` argument to the field in the index definition to allow this. + --> schema.prisma:10 +  |  +  9 |  + 10 |  @@id([firstName, lastName]) +  |  + "#]]; + + expect_error(schema, &expectation); +} + +#[test] +fn polygon_type_should_fail_on_id() { + let schema = indoc! {r#" + datasource db { + provider = "mysql" + url = env("DATABASE_URL") + } + + model User { + firstName GeoJson @db.Polygon + lastName GeoJson @db.Polygon + + @@id([firstName, lastName]) + } + "#}; + + let expectation = expect![[r#" + error: Native type `Polygon` of MySQL cannot be used on a field that is `@id` or `@@id`. Please use the `length` argument to the field in the index definition to allow this. + --> schema.prisma:10 +  |  +  9 |  + 10 |  @@id([firstName, lastName]) +  |  + "#]]; + + expect_error(schema, &expectation); +} + +#[test] +fn multipoint_type_should_fail_on_id() { + let schema = indoc! {r#" + datasource db { + provider = "mysql" + url = env("DATABASE_URL") + } + + model User { + firstName GeoJson @db.MultiPoint + lastName GeoJson @db.MultiPoint + + @@id([firstName, lastName]) + } + "#}; + + let expectation = expect![[r#" + error: Native type `MultiPoint` of MySQL cannot be used on a field that is `@id` or `@@id`. Please use the `length` argument to the field in the index definition to allow this. + --> schema.prisma:10 +  |  +  9 |  + 10 |  @@id([firstName, lastName]) +  |  + "#]]; + + expect_error(schema, &expectation); +} + +#[test] +fn multilinestring_type_should_fail_on_id() { + let schema = indoc! {r#" + datasource db { + provider = "mysql" + url = env("DATABASE_URL") + } + + model User { + firstName GeoJson @db.MultiLineString + lastName GeoJson @db.MultiLineString + + @@id([firstName, lastName]) + } + "#}; + + let expectation = expect![[r#" + error: Native type `MultiLineString` of MySQL cannot be used on a field that is `@id` or `@@id`. Please use the `length` argument to the field in the index definition to allow this. + --> schema.prisma:10 +  |  +  9 |  + 10 |  @@id([firstName, lastName]) +  |  + "#]]; + + expect_error(schema, &expectation); +} + +#[test] +fn multipolygon_type_should_fail_on_id() { + let schema = indoc! {r#" + datasource db { + provider = "mysql" + url = env("DATABASE_URL") + } + + model User { + firstName GeoJson @db.MultiPolygon + lastName GeoJson @db.MultiPolygon + + @@id([firstName, lastName]) + } + "#}; + + let expectation = expect![[r#" + error: Native type `MultiPolygon` of MySQL cannot be used on a field that is `@id` or `@@id`. Please use the `length` argument to the field in the index definition to allow this. + --> schema.prisma:10 +  |  +  9 |  + 10 |  @@id([firstName, lastName]) +  |  + "#]]; + + expect_error(schema, &expectation); +} + +#[test] +fn geometrycollection_type_should_fail_on_id() { + let schema = indoc! {r#" + datasource db { + provider = "mysql" + url = env("DATABASE_URL") + } + + model User { + firstName GeoJson @db.GeometryCollection + lastName GeoJson @db.GeometryCollection + + @@id([firstName, lastName]) + } + "#}; + + let expectation = expect![[r#" + error: Native type `GeometryCollection` of MySQL cannot be used on a field that is `@id` or `@@id`. Please use the `length` argument to the field in the index definition to allow this. + --> schema.prisma:10 +  |  +  9 |  + 10 |  @@id([firstName, lastName]) +  |  + "#]]; + + expect_error(schema, &expectation); +} + +#[test] +fn geojson_type_should_fail_on_invalid_srid() { + let schema = indoc! {r#" + datasource db { + provider = "mysql" + url = env("DATABASE_URL") + } + + model User { + id Int @id + geom1 GeoJson @db.Geometry(3857) + geom2 GeoJson @db.Point(3857) + geom3 GeoJson @db.LineString(3857) + geom4 GeoJson @db.Polygon(3857) + geom5 GeoJson @db.MultiPoint(3857) + geom6 GeoJson @db.MultiLineString(3857) + geom7 GeoJson @db.MultiPolygon(3857) + geom8 GeoJson @db.GeometryCollection(3857) + } + "#}; + + let expectation = expect![[r#" + error: Argument M is out of range for native type `Geometry(3857)` of MySQL: GeoJson SRID must be 4326. + --> schema.prisma:8 +  |  +  7 |  id Int @id +  8 |  geom1 GeoJson @db.Geometry(3857) +  |  + error: Argument M is out of range for native type `Point(3857)` of MySQL: GeoJson SRID must be 4326. + --> schema.prisma:9 +  |  +  8 |  geom1 GeoJson @db.Geometry(3857) +  9 |  geom2 GeoJson @db.Point(3857) +  |  + error: Argument M is out of range for native type `LineString(3857)` of MySQL: GeoJson SRID must be 4326. + --> schema.prisma:10 +  |  +  9 |  geom2 GeoJson @db.Point(3857) + 10 |  geom3 GeoJson @db.LineString(3857) +  |  + error: Argument M is out of range for native type `Polygon(3857)` of MySQL: GeoJson SRID must be 4326. + --> schema.prisma:11 +  |  + 10 |  geom3 GeoJson @db.LineString(3857) + 11 |  geom4 GeoJson @db.Polygon(3857) +  |  + error: Argument M is out of range for native type `MultiPoint(3857)` of MySQL: GeoJson SRID must be 4326. + --> schema.prisma:12 +  |  + 11 |  geom4 GeoJson @db.Polygon(3857) + 12 |  geom5 GeoJson @db.MultiPoint(3857) +  |  + error: Argument M is out of range for native type `MultiLineString(3857)` of MySQL: GeoJson SRID must be 4326. + --> schema.prisma:13 +  |  + 12 |  geom5 GeoJson @db.MultiPoint(3857) + 13 |  geom6 GeoJson @db.MultiLineString(3857) +  |  + error: Argument M is out of range for native type `MultiPolygon(3857)` of MySQL: GeoJson SRID must be 4326. + --> schema.prisma:14 +  |  + 13 |  geom6 GeoJson @db.MultiLineString(3857) + 14 |  geom7 GeoJson @db.MultiPolygon(3857) +  |  + error: Argument M is out of range for native type `GeometryCollection(3857)` of MySQL: GeoJson SRID must be 4326. + --> schema.prisma:15 +  |  + 14 |  geom7 GeoJson @db.MultiPolygon(3857) + 15 |  geom8 GeoJson @db.GeometryCollection(3857) +  |  + "#]]; + + expect_error(schema, &expectation); +} + #[test] fn text_should_not_fail_on_length_prefixed_index() { let dml = indoc! {r#" diff --git a/psl/psl/tests/types/postgres_native_types.rs b/psl/psl/tests/types/postgres_native_types.rs index a2e71ad3b973..fca309beb801 100644 --- a/psl/psl/tests/types/postgres_native_types.rs +++ b/psl/psl/tests/types/postgres_native_types.rs @@ -232,3 +232,502 @@ fn xml_should_work_with_string_scalar_type() { .assert_has_scalar_field("dec") .assert_native_type(datamodel.connector, &PostgresType::Xml); } + +#[test] +fn postgis_specific_native_types_are_valid() { + let schema = indoc! {r#" + datasource db { + provider = "postgres" + url = env("TEST_DATABASE_URL") + } + + model NativeTypesTest { + id Int @id + geom_01 Geometry @db.Geometry(Geometry, 4326) + geom_02 Geometry @db.Geometry(GeometryZ, 4326) + geom_03 Geometry @db.Geometry(GeometryM, 4326) + geom_04 Geometry @db.Geometry(GeometryZM, 4326) + geom_05 Geometry @db.Geometry(Point, 4326) + geom_06 Geometry @db.Geometry(PointZ, 4326) + geom_07 Geometry @db.Geometry(PointM, 4326) + geom_08 Geometry @db.Geometry(PointZM, 4326) + geom_09 Geometry @db.Geometry(LineString, 4326) + geom_10 Geometry @db.Geometry(LineStringZ, 4326) + geom_11 Geometry @db.Geometry(LineStringM, 4326) + geom_12 Geometry @db.Geometry(LineStringZM, 4326) + geom_13 Geometry @db.Geometry(Polygon, 4326) + geom_14 Geometry @db.Geometry(PolygonZ, 4326) + geom_15 Geometry @db.Geometry(PolygonM, 4326) + geom_16 Geometry @db.Geometry(PolygonZM, 4326) + geom_17 Geometry @db.Geometry(MultiPoint, 4326) + geom_18 Geometry @db.Geometry(MultiPointZ, 4326) + geom_19 Geometry @db.Geometry(MultiPointM, 4326) + geom_20 Geometry @db.Geometry(MultiPointZM, 4326) + geom_21 Geometry @db.Geometry(MultiLineString, 4326) + geom_22 Geometry @db.Geometry(MultiLineStringZ, 4326) + geom_23 Geometry @db.Geometry(MultiLineStringM, 4326) + geom_24 Geometry @db.Geometry(MultiLineStringZM, 4326) + geom_25 Geometry @db.Geometry(MultiPolygon, 4326) + geom_26 Geometry @db.Geometry(MultiPolygonZ, 4326) + geom_27 Geometry @db.Geometry(MultiPolygonM, 4326) + geom_28 Geometry @db.Geometry(MultiPolygonZM, 4326) + geom_29 Geometry @db.Geometry(GeometryCollection, 4326) + geom_30 Geometry @db.Geometry(GeometryCollectionZ, 4326) + geom_31 Geometry @db.Geometry(GeometryCollectionM, 4326) + geom_32 Geometry @db.Geometry(GeometryCollectionZM, 4326) + geom_33 Geometry @db.Geometry(CircularString, 4326) + geom_34 Geometry @db.Geometry(CircularStringZ, 4326) + geom_35 Geometry @db.Geometry(CircularStringM, 4326) + geom_36 Geometry @db.Geometry(CircularStringZM, 4326) + geom_37 Geometry @db.Geometry(CompoundCurve, 4326) + geom_38 Geometry @db.Geometry(CompoundCurveZ, 4326) + geom_39 Geometry @db.Geometry(CompoundCurveM, 4326) + geom_40 Geometry @db.Geometry(CompoundCurveZM, 4326) + geom_41 Geometry @db.Geometry(CurvePolygon, 4326) + geom_42 Geometry @db.Geometry(CurvePolygonZ, 4326) + geom_43 Geometry @db.Geometry(CurvePolygonM, 4326) + geom_44 Geometry @db.Geometry(CurvePolygonZM, 4326) + geom_45 Geometry @db.Geometry(MultiCurve, 4326) + geom_46 Geometry @db.Geometry(MultiCurveZ, 4326) + geom_47 Geometry @db.Geometry(MultiCurveM, 4326) + geom_48 Geometry @db.Geometry(MultiCurveZM, 4326) + geom_49 Geometry @db.Geometry(MultiSurface, 4326) + geom_50 Geometry @db.Geometry(MultiSurfaceZ, 4326) + geom_51 Geometry @db.Geometry(MultiSurfaceM, 4326) + geom_52 Geometry @db.Geometry(MultiSurfaceZM, 4326) + geom_53 Geometry @db.Geometry(PolyhedralSurface, 4326) + geom_54 Geometry @db.Geometry(PolyhedralSurfaceZ, 4326) + geom_55 Geometry @db.Geometry(PolyhedralSurfaceM, 4326) + geom_56 Geometry @db.Geometry(PolyhedralSurfaceZM, 4326) + geom_57 Geometry @db.Geometry(Tin, 4326) + geom_58 Geometry @db.Geometry(TinZ, 4326) + geom_59 Geometry @db.Geometry(TinM, 4326) + geom_60 Geometry @db.Geometry(TinZM, 4326) + geom_61 Geometry @db.Geometry(Triangle, 4326) + geom_62 Geometry @db.Geometry(TriangleZ, 4326) + geom_63 Geometry @db.Geometry(TriangleM, 4326) + geom_64 Geometry @db.Geometry(TriangleZM, 4326) + geog_01 Geometry @db.Geography(Geometry, 4326) + geog_02 Geometry @db.Geography(GeometryZ, 4326) + geog_03 Geometry @db.Geography(GeometryM, 4326) + geog_04 Geometry @db.Geography(GeometryZM, 4326) + geog_05 Geometry @db.Geography(Point, 4326) + geog_06 Geometry @db.Geography(PointZ, 4326) + geog_07 Geometry @db.Geography(PointM, 4326) + geog_08 Geometry @db.Geography(PointZM, 4326) + geog_09 Geometry @db.Geography(LineString, 4326) + geog_10 Geometry @db.Geography(LineStringZ, 4326) + geog_11 Geometry @db.Geography(LineStringM, 4326) + geog_12 Geometry @db.Geography(LineStringZM, 4326) + geog_13 Geometry @db.Geography(Polygon, 4326) + geog_14 Geometry @db.Geography(PolygonZ, 4326) + geog_15 Geometry @db.Geography(PolygonM, 4326) + geog_16 Geometry @db.Geography(PolygonZM, 4326) + geog_17 Geometry @db.Geography(MultiPoint, 4326) + geog_18 Geometry @db.Geography(MultiPointZ, 4326) + geog_19 Geometry @db.Geography(MultiPointM, 4326) + geog_20 Geometry @db.Geography(MultiPointZM, 4326) + geog_21 Geometry @db.Geography(MultiLineString, 4326) + geog_22 Geometry @db.Geography(MultiLineStringZ, 4326) + geog_23 Geometry @db.Geography(MultiLineStringM, 4326) + geog_24 Geometry @db.Geography(MultiLineStringZM, 4326) + geog_25 Geometry @db.Geography(MultiPolygon, 4326) + geog_26 Geometry @db.Geography(MultiPolygonZ, 4326) + geog_27 Geometry @db.Geography(MultiPolygonM, 4326) + geog_28 Geometry @db.Geography(MultiPolygonZM, 4326) + geog_29 Geometry @db.Geography(GeometryCollection, 4326) + geog_30 Geometry @db.Geography(GeometryCollectionZ, 4326) + geog_31 Geometry @db.Geography(GeometryCollectionM, 4326) + geog_32 Geometry @db.Geography(GeometryCollectionZM, 4326) + geog_33 Geometry @db.Geography(CircularString, 4326) + geog_34 Geometry @db.Geography(CircularStringZ, 4326) + geog_35 Geometry @db.Geography(CircularStringM, 4326) + geog_36 Geometry @db.Geography(CircularStringZM, 4326) + geog_37 Geometry @db.Geography(CompoundCurve, 4326) + geog_38 Geometry @db.Geography(CompoundCurveZ, 4326) + geog_39 Geometry @db.Geography(CompoundCurveM, 4326) + geog_40 Geometry @db.Geography(CompoundCurveZM, 4326) + geog_41 Geometry @db.Geography(CurvePolygon, 4326) + geog_42 Geometry @db.Geography(CurvePolygonZ, 4326) + geog_43 Geometry @db.Geography(CurvePolygonM, 4326) + geog_44 Geometry @db.Geography(CurvePolygonZM, 4326) + geog_45 Geometry @db.Geography(MultiCurve, 4326) + geog_46 Geometry @db.Geography(MultiCurveZ, 4326) + geog_47 Geometry @db.Geography(MultiCurveM, 4326) + geog_48 Geometry @db.Geography(MultiCurveZM, 4326) + geog_49 Geometry @db.Geography(MultiSurface, 4326) + geog_50 Geometry @db.Geography(MultiSurfaceZ, 4326) + geog_51 Geometry @db.Geography(MultiSurfaceM, 4326) + geog_52 Geometry @db.Geography(MultiSurfaceZM, 4326) + geog_53 Geometry @db.Geography(PolyhedralSurface, 4326) + geog_54 Geometry @db.Geography(PolyhedralSurfaceZ, 4326) + geog_55 Geometry @db.Geography(PolyhedralSurfaceM, 4326) + geog_56 Geometry @db.Geography(PolyhedralSurfaceZM, 4326) + geog_57 Geometry @db.Geography(Tin, 4326) + geog_58 Geometry @db.Geography(TinZ, 4326) + geog_59 Geometry @db.Geography(TinM, 4326) + geog_60 Geometry @db.Geography(TinZM, 4326) + geog_61 Geometry @db.Geography(Triangle, 4326) + geog_62 Geometry @db.Geography(TriangleZ, 4326) + geog_63 Geometry @db.Geography(TriangleM, 4326) + geog_64 Geometry @db.Geography(TriangleZM, 4326) + } + "#}; + + psl::parse_schema(schema).unwrap(); +} + +#[test] +fn should_fail_on_geojson_when_incompatible_geometry_type() { + let dml = indoc! {r#" + datasource db { + provider = "postgres" + url = env("TEST_DATABASE_URL") + } + + model Blog { + id Int @id + geom_01 GeoJson @db.Geometry(CircularString, 4326) + geom_02 GeoJson @db.Geometry(CircularStringZ, 4326) + geom_03 GeoJson @db.Geometry(CircularStringM, 4326) + geom_04 GeoJson @db.Geometry(CircularStringZM, 4326) + geom_05 GeoJson @db.Geometry(CompoundCurve, 4326) + geom_06 GeoJson @db.Geometry(CompoundCurveZ, 4326) + geom_07 GeoJson @db.Geometry(CompoundCurveM, 4326) + geom_08 GeoJson @db.Geometry(CompoundCurveZM, 4326) + geom_09 GeoJson @db.Geometry(CurvePolygon, 4326) + geom_10 GeoJson @db.Geometry(CurvePolygonZ, 4326) + geom_11 GeoJson @db.Geometry(CurvePolygonM, 4326) + geom_12 GeoJson @db.Geometry(CurvePolygonZM, 4326) + geom_13 GeoJson @db.Geometry(MultiCurve, 4326) + geom_14 GeoJson @db.Geometry(MultiCurveZ, 4326) + geom_15 GeoJson @db.Geometry(MultiCurveM, 4326) + geom_16 GeoJson @db.Geometry(MultiCurveZM, 4326) + geom_17 GeoJson @db.Geometry(MultiSurface, 4326) + geom_18 GeoJson @db.Geometry(MultiSurfaceZ, 4326) + geom_19 GeoJson @db.Geometry(MultiSurfaceM, 4326) + geom_20 GeoJson @db.Geometry(MultiSurfaceZM, 4326) + geom_21 GeoJson @db.Geometry(PolyhedralSurface, 4326) + geom_22 GeoJson @db.Geometry(PolyhedralSurfaceZ, 4326) + geom_23 GeoJson @db.Geometry(PolyhedralSurfaceM, 4326) + geom_24 GeoJson @db.Geometry(PolyhedralSurfaceZM, 4326) + geog_01 GeoJson @db.Geography(CircularString, 4326) + geog_02 GeoJson @db.Geography(CircularStringZ, 4326) + geog_03 GeoJson @db.Geography(CircularStringM, 4326) + geog_04 GeoJson @db.Geography(CircularStringZM, 4326) + geog_05 GeoJson @db.Geography(CompoundCurve, 4326) + geog_06 GeoJson @db.Geography(CompoundCurveZ, 4326) + geog_07 GeoJson @db.Geography(CompoundCurveM, 4326) + geog_08 GeoJson @db.Geography(CompoundCurveZM, 4326) + geog_09 GeoJson @db.Geography(CurvePolygon, 4326) + geog_10 GeoJson @db.Geography(CurvePolygonZ, 4326) + geog_11 GeoJson @db.Geography(CurvePolygonM, 4326) + geog_12 GeoJson @db.Geography(CurvePolygonZM, 4326) + geog_13 GeoJson @db.Geography(MultiCurve, 4326) + geog_14 GeoJson @db.Geography(MultiCurveZ, 4326) + geog_15 GeoJson @db.Geography(MultiCurveM, 4326) + geog_16 GeoJson @db.Geography(MultiCurveZM, 4326) + geog_17 GeoJson @db.Geography(MultiSurface, 4326) + geog_18 GeoJson @db.Geography(MultiSurfaceZ, 4326) + geog_19 GeoJson @db.Geography(MultiSurfaceM, 4326) + geog_20 GeoJson @db.Geography(MultiSurfaceZM, 4326) + geog_21 GeoJson @db.Geography(PolyhedralSurface, 4326) + geog_22 GeoJson @db.Geography(PolyhedralSurfaceZ, 4326) + geog_23 GeoJson @db.Geography(PolyhedralSurfaceM, 4326) + geog_24 GeoJson @db.Geography(PolyhedralSurfaceZM, 4326) + } + "#}; + + let expectation = expect![[r#" + error: Argument M is out of range for native type `Geometry(CircularString,4326)` of Postgres: CircularString isn't compatible with GeoJson. + --> schema.prisma:8 +  |  +  7 |  id Int @id +  8 |  geom_01 GeoJson @db.Geometry(CircularString, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CircularStringZ,4326)` of Postgres: CircularStringZ isn't compatible with GeoJson. + --> schema.prisma:9 +  |  +  8 |  geom_01 GeoJson @db.Geometry(CircularString, 4326) +  9 |  geom_02 GeoJson @db.Geometry(CircularStringZ, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CircularStringM,4326)` of Postgres: CircularStringM isn't compatible with GeoJson. + --> schema.prisma:10 +  |  +  9 |  geom_02 GeoJson @db.Geometry(CircularStringZ, 4326) + 10 |  geom_03 GeoJson @db.Geometry(CircularStringM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CircularStringZM,4326)` of Postgres: CircularStringZM isn't compatible with GeoJson. + --> schema.prisma:11 +  |  + 10 |  geom_03 GeoJson @db.Geometry(CircularStringM, 4326) + 11 |  geom_04 GeoJson @db.Geometry(CircularStringZM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CompoundCurve,4326)` of Postgres: CompoundCurve isn't compatible with GeoJson. + --> schema.prisma:12 +  |  + 11 |  geom_04 GeoJson @db.Geometry(CircularStringZM, 4326) + 12 |  geom_05 GeoJson @db.Geometry(CompoundCurve, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CompoundCurveZ,4326)` of Postgres: CompoundCurveZ isn't compatible with GeoJson. + --> schema.prisma:13 +  |  + 12 |  geom_05 GeoJson @db.Geometry(CompoundCurve, 4326) + 13 |  geom_06 GeoJson @db.Geometry(CompoundCurveZ, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CompoundCurveM,4326)` of Postgres: CompoundCurveM isn't compatible with GeoJson. + --> schema.prisma:14 +  |  + 13 |  geom_06 GeoJson @db.Geometry(CompoundCurveZ, 4326) + 14 |  geom_07 GeoJson @db.Geometry(CompoundCurveM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CompoundCurveZM,4326)` of Postgres: CompoundCurveZM isn't compatible with GeoJson. + --> schema.prisma:15 +  |  + 14 |  geom_07 GeoJson @db.Geometry(CompoundCurveM, 4326) + 15 |  geom_08 GeoJson @db.Geometry(CompoundCurveZM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CurvePolygon,4326)` of Postgres: CurvePolygon isn't compatible with GeoJson. + --> schema.prisma:16 +  |  + 15 |  geom_08 GeoJson @db.Geometry(CompoundCurveZM, 4326) + 16 |  geom_09 GeoJson @db.Geometry(CurvePolygon, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CurvePolygonZ,4326)` of Postgres: CurvePolygonZ isn't compatible with GeoJson. + --> schema.prisma:17 +  |  + 16 |  geom_09 GeoJson @db.Geometry(CurvePolygon, 4326) + 17 |  geom_10 GeoJson @db.Geometry(CurvePolygonZ, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CurvePolygonM,4326)` of Postgres: CurvePolygonM isn't compatible with GeoJson. + --> schema.prisma:18 +  |  + 17 |  geom_10 GeoJson @db.Geometry(CurvePolygonZ, 4326) + 18 |  geom_11 GeoJson @db.Geometry(CurvePolygonM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CurvePolygonZM,4326)` of Postgres: CurvePolygonZM isn't compatible with GeoJson. + --> schema.prisma:19 +  |  + 18 |  geom_11 GeoJson @db.Geometry(CurvePolygonM, 4326) + 19 |  geom_12 GeoJson @db.Geometry(CurvePolygonZM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiCurve,4326)` of Postgres: MultiCurve isn't compatible with GeoJson. + --> schema.prisma:20 +  |  + 19 |  geom_12 GeoJson @db.Geometry(CurvePolygonZM, 4326) + 20 |  geom_13 GeoJson @db.Geometry(MultiCurve, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiCurveZ,4326)` of Postgres: MultiCurveZ isn't compatible with GeoJson. + --> schema.prisma:21 +  |  + 20 |  geom_13 GeoJson @db.Geometry(MultiCurve, 4326) + 21 |  geom_14 GeoJson @db.Geometry(MultiCurveZ, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiCurveM,4326)` of Postgres: MultiCurveM isn't compatible with GeoJson. + --> schema.prisma:22 +  |  + 21 |  geom_14 GeoJson @db.Geometry(MultiCurveZ, 4326) + 22 |  geom_15 GeoJson @db.Geometry(MultiCurveM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiCurveZM,4326)` of Postgres: MultiCurveZM isn't compatible with GeoJson. + --> schema.prisma:23 +  |  + 22 |  geom_15 GeoJson @db.Geometry(MultiCurveM, 4326) + 23 |  geom_16 GeoJson @db.Geometry(MultiCurveZM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiSurface,4326)` of Postgres: MultiSurface isn't compatible with GeoJson. + --> schema.prisma:24 +  |  + 23 |  geom_16 GeoJson @db.Geometry(MultiCurveZM, 4326) + 24 |  geom_17 GeoJson @db.Geometry(MultiSurface, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiSurfaceZ,4326)` of Postgres: MultiSurfaceZ isn't compatible with GeoJson. + --> schema.prisma:25 +  |  + 24 |  geom_17 GeoJson @db.Geometry(MultiSurface, 4326) + 25 |  geom_18 GeoJson @db.Geometry(MultiSurfaceZ, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiSurfaceM,4326)` of Postgres: MultiSurfaceM isn't compatible with GeoJson. + --> schema.prisma:26 +  |  + 25 |  geom_18 GeoJson @db.Geometry(MultiSurfaceZ, 4326) + 26 |  geom_19 GeoJson @db.Geometry(MultiSurfaceM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiSurfaceZM,4326)` of Postgres: MultiSurfaceZM isn't compatible with GeoJson. + --> schema.prisma:27 +  |  + 26 |  geom_19 GeoJson @db.Geometry(MultiSurfaceM, 4326) + 27 |  geom_20 GeoJson @db.Geometry(MultiSurfaceZM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(PolyhedralSurface,4326)` of Postgres: PolyhedralSurface isn't compatible with GeoJson. + --> schema.prisma:28 +  |  + 27 |  geom_20 GeoJson @db.Geometry(MultiSurfaceZM, 4326) + 28 |  geom_21 GeoJson @db.Geometry(PolyhedralSurface, 4326) +  |  + error: Argument M is out of range for native type `Geometry(PolyhedralSurfaceZ,4326)` of Postgres: PolyhedralSurfaceZ isn't compatible with GeoJson. + --> schema.prisma:29 +  |  + 28 |  geom_21 GeoJson @db.Geometry(PolyhedralSurface, 4326) + 29 |  geom_22 GeoJson @db.Geometry(PolyhedralSurfaceZ, 4326) +  |  + error: Argument M is out of range for native type `Geometry(PolyhedralSurfaceM,4326)` of Postgres: PolyhedralSurfaceM isn't compatible with GeoJson. + --> schema.prisma:30 +  |  + 29 |  geom_22 GeoJson @db.Geometry(PolyhedralSurfaceZ, 4326) + 30 |  geom_23 GeoJson @db.Geometry(PolyhedralSurfaceM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(PolyhedralSurfaceZM,4326)` of Postgres: PolyhedralSurfaceZM isn't compatible with GeoJson. + --> schema.prisma:31 +  |  + 30 |  geom_23 GeoJson @db.Geometry(PolyhedralSurfaceM, 4326) + 31 |  geom_24 GeoJson @db.Geometry(PolyhedralSurfaceZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(CircularString,4326)` of Postgres: CircularString isn't compatible with GeoJson. + --> schema.prisma:32 +  |  + 31 |  geom_24 GeoJson @db.Geometry(PolyhedralSurfaceZM, 4326) + 32 |  geog_01 GeoJson @db.Geography(CircularString, 4326) +  |  + error: Argument M is out of range for native type `Geography(CircularStringZ,4326)` of Postgres: CircularStringZ isn't compatible with GeoJson. + --> schema.prisma:33 +  |  + 32 |  geog_01 GeoJson @db.Geography(CircularString, 4326) + 33 |  geog_02 GeoJson @db.Geography(CircularStringZ, 4326) +  |  + error: Argument M is out of range for native type `Geography(CircularStringM,4326)` of Postgres: CircularStringM isn't compatible with GeoJson. + --> schema.prisma:34 +  |  + 33 |  geog_02 GeoJson @db.Geography(CircularStringZ, 4326) + 34 |  geog_03 GeoJson @db.Geography(CircularStringM, 4326) +  |  + error: Argument M is out of range for native type `Geography(CircularStringZM,4326)` of Postgres: CircularStringZM isn't compatible with GeoJson. + --> schema.prisma:35 +  |  + 34 |  geog_03 GeoJson @db.Geography(CircularStringM, 4326) + 35 |  geog_04 GeoJson @db.Geography(CircularStringZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(CompoundCurve,4326)` of Postgres: CompoundCurve isn't compatible with GeoJson. + --> schema.prisma:36 +  |  + 35 |  geog_04 GeoJson @db.Geography(CircularStringZM, 4326) + 36 |  geog_05 GeoJson @db.Geography(CompoundCurve, 4326) +  |  + error: Argument M is out of range for native type `Geography(CompoundCurveZ,4326)` of Postgres: CompoundCurveZ isn't compatible with GeoJson. + --> schema.prisma:37 +  |  + 36 |  geog_05 GeoJson @db.Geography(CompoundCurve, 4326) + 37 |  geog_06 GeoJson @db.Geography(CompoundCurveZ, 4326) +  |  + error: Argument M is out of range for native type `Geography(CompoundCurveM,4326)` of Postgres: CompoundCurveM isn't compatible with GeoJson. + --> schema.prisma:38 +  |  + 37 |  geog_06 GeoJson @db.Geography(CompoundCurveZ, 4326) + 38 |  geog_07 GeoJson @db.Geography(CompoundCurveM, 4326) +  |  + error: Argument M is out of range for native type `Geography(CompoundCurveZM,4326)` of Postgres: CompoundCurveZM isn't compatible with GeoJson. + --> schema.prisma:39 +  |  + 38 |  geog_07 GeoJson @db.Geography(CompoundCurveM, 4326) + 39 |  geog_08 GeoJson @db.Geography(CompoundCurveZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(CurvePolygon,4326)` of Postgres: CurvePolygon isn't compatible with GeoJson. + --> schema.prisma:40 +  |  + 39 |  geog_08 GeoJson @db.Geography(CompoundCurveZM, 4326) + 40 |  geog_09 GeoJson @db.Geography(CurvePolygon, 4326) +  |  + error: Argument M is out of range for native type `Geography(CurvePolygonZ,4326)` of Postgres: CurvePolygonZ isn't compatible with GeoJson. + --> schema.prisma:41 +  |  + 40 |  geog_09 GeoJson @db.Geography(CurvePolygon, 4326) + 41 |  geog_10 GeoJson @db.Geography(CurvePolygonZ, 4326) +  |  + error: Argument M is out of range for native type `Geography(CurvePolygonM,4326)` of Postgres: CurvePolygonM isn't compatible with GeoJson. + --> schema.prisma:42 +  |  + 41 |  geog_10 GeoJson @db.Geography(CurvePolygonZ, 4326) + 42 |  geog_11 GeoJson @db.Geography(CurvePolygonM, 4326) +  |  + error: Argument M is out of range for native type `Geography(CurvePolygonZM,4326)` of Postgres: CurvePolygonZM isn't compatible with GeoJson. + --> schema.prisma:43 +  |  + 42 |  geog_11 GeoJson @db.Geography(CurvePolygonM, 4326) + 43 |  geog_12 GeoJson @db.Geography(CurvePolygonZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiCurve,4326)` of Postgres: MultiCurve isn't compatible with GeoJson. + --> schema.prisma:44 +  |  + 43 |  geog_12 GeoJson @db.Geography(CurvePolygonZM, 4326) + 44 |  geog_13 GeoJson @db.Geography(MultiCurve, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiCurveZ,4326)` of Postgres: MultiCurveZ isn't compatible with GeoJson. + --> schema.prisma:45 +  |  + 44 |  geog_13 GeoJson @db.Geography(MultiCurve, 4326) + 45 |  geog_14 GeoJson @db.Geography(MultiCurveZ, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiCurveM,4326)` of Postgres: MultiCurveM isn't compatible with GeoJson. + --> schema.prisma:46 +  |  + 45 |  geog_14 GeoJson @db.Geography(MultiCurveZ, 4326) + 46 |  geog_15 GeoJson @db.Geography(MultiCurveM, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiCurveZM,4326)` of Postgres: MultiCurveZM isn't compatible with GeoJson. + --> schema.prisma:47 +  |  + 46 |  geog_15 GeoJson @db.Geography(MultiCurveM, 4326) + 47 |  geog_16 GeoJson @db.Geography(MultiCurveZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiSurface,4326)` of Postgres: MultiSurface isn't compatible with GeoJson. + --> schema.prisma:48 +  |  + 47 |  geog_16 GeoJson @db.Geography(MultiCurveZM, 4326) + 48 |  geog_17 GeoJson @db.Geography(MultiSurface, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiSurfaceZ,4326)` of Postgres: MultiSurfaceZ isn't compatible with GeoJson. + --> schema.prisma:49 +  |  + 48 |  geog_17 GeoJson @db.Geography(MultiSurface, 4326) + 49 |  geog_18 GeoJson @db.Geography(MultiSurfaceZ, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiSurfaceM,4326)` of Postgres: MultiSurfaceM isn't compatible with GeoJson. + --> schema.prisma:50 +  |  + 49 |  geog_18 GeoJson @db.Geography(MultiSurfaceZ, 4326) + 50 |  geog_19 GeoJson @db.Geography(MultiSurfaceM, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiSurfaceZM,4326)` of Postgres: MultiSurfaceZM isn't compatible with GeoJson. + --> schema.prisma:51 +  |  + 50 |  geog_19 GeoJson @db.Geography(MultiSurfaceM, 4326) + 51 |  geog_20 GeoJson @db.Geography(MultiSurfaceZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(PolyhedralSurface,4326)` of Postgres: PolyhedralSurface isn't compatible with GeoJson. + --> schema.prisma:52 +  |  + 51 |  geog_20 GeoJson @db.Geography(MultiSurfaceZM, 4326) + 52 |  geog_21 GeoJson @db.Geography(PolyhedralSurface, 4326) +  |  + error: Argument M is out of range for native type `Geography(PolyhedralSurfaceZ,4326)` of Postgres: PolyhedralSurfaceZ isn't compatible with GeoJson. + --> schema.prisma:53 +  |  + 52 |  geog_21 GeoJson @db.Geography(PolyhedralSurface, 4326) + 53 |  geog_22 GeoJson @db.Geography(PolyhedralSurfaceZ, 4326) +  |  + error: Argument M is out of range for native type `Geography(PolyhedralSurfaceM,4326)` of Postgres: PolyhedralSurfaceM isn't compatible with GeoJson. + --> schema.prisma:54 +  |  + 53 |  geog_22 GeoJson @db.Geography(PolyhedralSurfaceZ, 4326) + 54 |  geog_23 GeoJson @db.Geography(PolyhedralSurfaceM, 4326) +  |  + error: Argument M is out of range for native type `Geography(PolyhedralSurfaceZM,4326)` of Postgres: PolyhedralSurfaceZM isn't compatible with GeoJson. + --> schema.prisma:55 +  |  + 54 |  geog_23 GeoJson @db.Geography(PolyhedralSurfaceM, 4326) + 55 |  geog_24 GeoJson @db.Geography(PolyhedralSurfaceZM, 4326) +  |  + "#]]; + + expect_error(dml, &expectation); +} diff --git a/psl/psl/tests/types/sqlite_native_types.rs b/psl/psl/tests/types/sqlite_native_types.rs new file mode 100644 index 000000000000..c9c4133d3a35 --- /dev/null +++ b/psl/psl/tests/types/sqlite_native_types.rs @@ -0,0 +1,487 @@ +use crate::common::*; +use expect_test::expect; + +#[test] +fn sqlite_specific_native_types_are_valid() { + let schema = indoc! {r#" + datasource db { + provider = "sqlite" + url = "file:test.db" + } + + model NativeTypesTest { + id Int @id + geomcol1 Geometry @db.Geometry(Geometry, 4326) + geomcol2 Geometry @db.Geometry(GeometryZ, 4326) + geomcol3 Geometry @db.Geometry(GeometryM, 4326) + geomcol4 Geometry @db.Geometry(GeometryZM, 4326) + geomcol5 Geometry @db.Geometry(Point, 4326) + geomcol6 Geometry @db.Geometry(PointZ, 4326) + geomcol7 Geometry @db.Geometry(PointM, 4326) + geomcol8 Geometry @db.Geometry(PointZM, 4326) + geomcol9 Geometry @db.Geometry(Point, 4326) + geomcol10 Geometry @db.Geometry(PointZ, 4326) + geomcol11 Geometry @db.Geometry(PointM, 4326) + geomcol12 Geometry @db.Geometry(PointZM, 4326) + geomcol13 Geometry @db.Geometry(LineString, 4326) + geomcol14 Geometry @db.Geometry(LineStringZ, 4326) + geomcol15 Geometry @db.Geometry(LineStringM, 4326) + geomcol16 Geometry @db.Geometry(LineStringZM, 4326) + geomcol17 Geometry @db.Geometry(Polygon, 4326) + geomcol18 Geometry @db.Geometry(PolygonZ, 4326) + geomcol19 Geometry @db.Geometry(PolygonM, 4326) + geomcol20 Geometry @db.Geometry(PolygonZM, 4326) + geomcol21 Geometry @db.Geometry(MultiPoint, 4326) + geomcol22 Geometry @db.Geometry(MultiPointZ, 4326) + geomcol23 Geometry @db.Geometry(MultiPointM, 4326) + geomcol24 Geometry @db.Geometry(MultiPointZM, 4326) + geomcol25 Geometry @db.Geometry(MultiLineString, 4326) + geomcol26 Geometry @db.Geometry(MultiLineStringZ, 4326) + geomcol27 Geometry @db.Geometry(MultiLineStringM, 4326) + geomcol28 Geometry @db.Geometry(MultiLineStringZM, 4326) + geomcol29 Geometry @db.Geometry(MultiPolygon, 4326) + geomcol30 Geometry @db.Geometry(MultiPolygonZ, 4326) + geomcol31 Geometry @db.Geometry(MultiPolygonM, 4326) + geomcol32 Geometry @db.Geometry(MultiPolygonZM, 4326) + geomcol33 Geometry @db.Geometry(GeometryCollection, 4326) + geomcol34 Geometry @db.Geometry(GeometryCollectionZ, 4326) + geomcol35 Geometry @db.Geometry(GeometryCollectionM, 4326) + geomcol36 Geometry @db.Geometry(GeometryCollectionZM, 4326) + } + "#}; + + psl::parse_schema(schema).unwrap(); +} + +#[test] +fn should_fail_on_geojson_when_invalid_geometry_type() { + let dml = indoc! {r#" + datasource db { + provider = "sqlite" + url = "file:test.db" + } + + model Blog { + id Int @id + geom Geometry @db.Geometry(Invalid) + } + "#}; + + let expectation = expect![[r#" + error: Expected a geometry type and an optional srid, but found (Invalid). + --> schema.prisma:8 +  |  +  7 |  id Int @id +  8 |  geom Geometry @db.Geometry(Invalid) +  |  + "#]]; + + expect_error(dml, &expectation); +} + +#[test] +fn should_fail_on_geojson_when_non_wgs84_srid() { + let schema = indoc! {r#" + datasource db { + provider = "sqlite" + url = "file:test.db" + } + + model User { + id Int @id + geom GeoJson @db.Geometry(Point, 3857) + } + "#}; + + let expectation = expect![[r#" + error: Argument M is out of range for native type `Geometry(Point,3857)` of sqlite: GeoJson SRID must be 4326. + --> schema.prisma:8 +  |  +  7 |  id Int @id +  8 |  geom GeoJson @db.Geometry(Point, 3857) +  |  + "#]]; + + expect_error(schema, &expectation); +} + +#[test] +fn should_fail_on_geometry_when_out_of_bound_srid() { + let schema = indoc! {r#" + datasource db { + provider = "sqlite" + url = "file:test.db" + } + + model User { + id Int @id + geom Geometry @db.Geometry(Point, -2) + } + "#}; + + let expectation = expect![[r#" + error: Argument M is out of range for native type `Geometry(Point,-2)` of sqlite: SRID must be superior or equal to -1. + --> schema.prisma:8 +  |  +  7 |  id Int @id +  8 |  geom Geometry @db.Geometry(Point, -2) +  |  + "#]]; + + expect_error(schema, &expectation); +} + +#[test] +fn should_fail_on_geometry_when_extra_geometry_type() { + let schema = indoc! {r#" + datasource db { + provider = "sqlite" + url = "file:test.db" + } + + model User { + id Int @id + geom_00 Geometry @db.Geometry(CircularString, 4326) + geom_01 Geometry @db.Geometry(CircularStringZ, 4326) + geom_02 Geometry @db.Geometry(CircularStringM, 4326) + geom_03 Geometry @db.Geometry(CircularStringZM, 4326) + geom_04 Geometry @db.Geometry(CompoundCurve, 4326) + geom_05 Geometry @db.Geometry(CompoundCurveZ, 4326) + geom_06 Geometry @db.Geometry(CompoundCurveM, 4326) + geom_07 Geometry @db.Geometry(CompoundCurveZM, 4326) + geom_08 Geometry @db.Geometry(CurvePolygon, 4326) + geom_09 Geometry @db.Geometry(CurvePolygonZ, 4326) + geom_10 Geometry @db.Geometry(CurvePolygonM, 4326) + geom_11 Geometry @db.Geometry(CurvePolygonZM, 4326) + geom_12 Geometry @db.Geometry(MultiCurve, 4326) + geom_13 Geometry @db.Geometry(MultiCurveZ, 4326) + geom_14 Geometry @db.Geometry(MultiCurveM, 4326) + geom_15 Geometry @db.Geometry(MultiCurveZM, 4326) + geom_16 Geometry @db.Geometry(MultiSurface, 4326) + geom_17 Geometry @db.Geometry(MultiSurfaceZ, 4326) + geom_18 Geometry @db.Geometry(MultiSurfaceM, 4326) + geom_19 Geometry @db.Geometry(MultiSurfaceZM, 4326) + geom_20 Geometry @db.Geometry(PolyhedralSurface, 4326) + geom_21 Geometry @db.Geometry(PolyhedralSurfaceZ, 4326) + geom_22 Geometry @db.Geometry(PolyhedralSurfaceM, 4326) + geom_23 Geometry @db.Geometry(PolyhedralSurfaceZM, 4326) + geog_00 Geometry @db.Geography(CircularString, 4326) + geog_01 Geometry @db.Geography(CircularStringZ, 4326) + geog_02 Geometry @db.Geography(CircularStringM, 4326) + geog_03 Geometry @db.Geography(CircularStringZM, 4326) + geog_04 Geometry @db.Geography(CompoundCurve, 4326) + geog_05 Geometry @db.Geography(CompoundCurveZ, 4326) + geog_06 Geometry @db.Geography(CompoundCurveM, 4326) + geog_07 Geometry @db.Geography(CompoundCurveZM, 4326) + geog_08 Geometry @db.Geography(CurvePolygon, 4326) + geog_09 Geometry @db.Geography(CurvePolygonZ, 4326) + geog_10 Geometry @db.Geography(CurvePolygonM, 4326) + geog_11 Geometry @db.Geography(CurvePolygonZM, 4326) + geog_12 Geometry @db.Geography(MultiCurve, 4326) + geog_13 Geometry @db.Geography(MultiCurveZ, 4326) + geog_14 Geometry @db.Geography(MultiCurveM, 4326) + geog_15 Geometry @db.Geography(MultiCurveZM, 4326) + geog_16 Geometry @db.Geography(MultiSurface, 4326) + geog_17 Geometry @db.Geography(MultiSurfaceZ, 4326) + geog_18 Geometry @db.Geography(MultiSurfaceM, 4326) + geog_19 Geometry @db.Geography(MultiSurfaceZM, 4326) + geog_20 Geometry @db.Geography(PolyhedralSurface, 4326) + geog_21 Geometry @db.Geography(PolyhedralSurfaceZ, 4326) + geog_22 Geometry @db.Geography(PolyhedralSurfaceM, 4326) + geog_23 Geometry @db.Geography(PolyhedralSurfaceZM, 4326) + } + "#}; + + let expectation = expect![[r#" + error: Argument M is out of range for native type `Geometry(CircularString,4326)` of sqlite: CircularString isn't supported for the current connector. + --> schema.prisma:8 +  |  +  7 |  id Int @id +  8 |  geom_00 Geometry @db.Geometry(CircularString, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CircularStringZ,4326)` of sqlite: CircularStringZ isn't supported for the current connector. + --> schema.prisma:9 +  |  +  8 |  geom_00 Geometry @db.Geometry(CircularString, 4326) +  9 |  geom_01 Geometry @db.Geometry(CircularStringZ, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CircularStringM,4326)` of sqlite: CircularStringM isn't supported for the current connector. + --> schema.prisma:10 +  |  +  9 |  geom_01 Geometry @db.Geometry(CircularStringZ, 4326) + 10 |  geom_02 Geometry @db.Geometry(CircularStringM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CircularStringZM,4326)` of sqlite: CircularStringZM isn't supported for the current connector. + --> schema.prisma:11 +  |  + 10 |  geom_02 Geometry @db.Geometry(CircularStringM, 4326) + 11 |  geom_03 Geometry @db.Geometry(CircularStringZM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CompoundCurve,4326)` of sqlite: CompoundCurve isn't supported for the current connector. + --> schema.prisma:12 +  |  + 11 |  geom_03 Geometry @db.Geometry(CircularStringZM, 4326) + 12 |  geom_04 Geometry @db.Geometry(CompoundCurve, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CompoundCurveZ,4326)` of sqlite: CompoundCurveZ isn't supported for the current connector. + --> schema.prisma:13 +  |  + 12 |  geom_04 Geometry @db.Geometry(CompoundCurve, 4326) + 13 |  geom_05 Geometry @db.Geometry(CompoundCurveZ, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CompoundCurveM,4326)` of sqlite: CompoundCurveM isn't supported for the current connector. + --> schema.prisma:14 +  |  + 13 |  geom_05 Geometry @db.Geometry(CompoundCurveZ, 4326) + 14 |  geom_06 Geometry @db.Geometry(CompoundCurveM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CompoundCurveZM,4326)` of sqlite: CompoundCurveZM isn't supported for the current connector. + --> schema.prisma:15 +  |  + 14 |  geom_06 Geometry @db.Geometry(CompoundCurveM, 4326) + 15 |  geom_07 Geometry @db.Geometry(CompoundCurveZM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CurvePolygon,4326)` of sqlite: CurvePolygon isn't supported for the current connector. + --> schema.prisma:16 +  |  + 15 |  geom_07 Geometry @db.Geometry(CompoundCurveZM, 4326) + 16 |  geom_08 Geometry @db.Geometry(CurvePolygon, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CurvePolygonZ,4326)` of sqlite: CurvePolygonZ isn't supported for the current connector. + --> schema.prisma:17 +  |  + 16 |  geom_08 Geometry @db.Geometry(CurvePolygon, 4326) + 17 |  geom_09 Geometry @db.Geometry(CurvePolygonZ, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CurvePolygonM,4326)` of sqlite: CurvePolygonM isn't supported for the current connector. + --> schema.prisma:18 +  |  + 17 |  geom_09 Geometry @db.Geometry(CurvePolygonZ, 4326) + 18 |  geom_10 Geometry @db.Geometry(CurvePolygonM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(CurvePolygonZM,4326)` of sqlite: CurvePolygonZM isn't supported for the current connector. + --> schema.prisma:19 +  |  + 18 |  geom_10 Geometry @db.Geometry(CurvePolygonM, 4326) + 19 |  geom_11 Geometry @db.Geometry(CurvePolygonZM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiCurve,4326)` of sqlite: MultiCurve isn't supported for the current connector. + --> schema.prisma:20 +  |  + 19 |  geom_11 Geometry @db.Geometry(CurvePolygonZM, 4326) + 20 |  geom_12 Geometry @db.Geometry(MultiCurve, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiCurveZ,4326)` of sqlite: MultiCurveZ isn't supported for the current connector. + --> schema.prisma:21 +  |  + 20 |  geom_12 Geometry @db.Geometry(MultiCurve, 4326) + 21 |  geom_13 Geometry @db.Geometry(MultiCurveZ, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiCurveM,4326)` of sqlite: MultiCurveM isn't supported for the current connector. + --> schema.prisma:22 +  |  + 21 |  geom_13 Geometry @db.Geometry(MultiCurveZ, 4326) + 22 |  geom_14 Geometry @db.Geometry(MultiCurveM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiCurveZM,4326)` of sqlite: MultiCurveZM isn't supported for the current connector. + --> schema.prisma:23 +  |  + 22 |  geom_14 Geometry @db.Geometry(MultiCurveM, 4326) + 23 |  geom_15 Geometry @db.Geometry(MultiCurveZM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiSurface,4326)` of sqlite: MultiSurface isn't supported for the current connector. + --> schema.prisma:24 +  |  + 23 |  geom_15 Geometry @db.Geometry(MultiCurveZM, 4326) + 24 |  geom_16 Geometry @db.Geometry(MultiSurface, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiSurfaceZ,4326)` of sqlite: MultiSurfaceZ isn't supported for the current connector. + --> schema.prisma:25 +  |  + 24 |  geom_16 Geometry @db.Geometry(MultiSurface, 4326) + 25 |  geom_17 Geometry @db.Geometry(MultiSurfaceZ, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiSurfaceM,4326)` of sqlite: MultiSurfaceM isn't supported for the current connector. + --> schema.prisma:26 +  |  + 25 |  geom_17 Geometry @db.Geometry(MultiSurfaceZ, 4326) + 26 |  geom_18 Geometry @db.Geometry(MultiSurfaceM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiSurfaceZM,4326)` of sqlite: MultiSurfaceZM isn't supported for the current connector. + --> schema.prisma:27 +  |  + 26 |  geom_18 Geometry @db.Geometry(MultiSurfaceM, 4326) + 27 |  geom_19 Geometry @db.Geometry(MultiSurfaceZM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(PolyhedralSurface,4326)` of sqlite: PolyhedralSurface isn't supported for the current connector. + --> schema.prisma:28 +  |  + 27 |  geom_19 Geometry @db.Geometry(MultiSurfaceZM, 4326) + 28 |  geom_20 Geometry @db.Geometry(PolyhedralSurface, 4326) +  |  + error: Argument M is out of range for native type `Geometry(PolyhedralSurfaceZ,4326)` of sqlite: PolyhedralSurfaceZ isn't supported for the current connector. + --> schema.prisma:29 +  |  + 28 |  geom_20 Geometry @db.Geometry(PolyhedralSurface, 4326) + 29 |  geom_21 Geometry @db.Geometry(PolyhedralSurfaceZ, 4326) +  |  + error: Argument M is out of range for native type `Geometry(PolyhedralSurfaceM,4326)` of sqlite: PolyhedralSurfaceM isn't supported for the current connector. + --> schema.prisma:30 +  |  + 29 |  geom_21 Geometry @db.Geometry(PolyhedralSurfaceZ, 4326) + 30 |  geom_22 Geometry @db.Geometry(PolyhedralSurfaceM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(PolyhedralSurfaceZM,4326)` of sqlite: PolyhedralSurfaceZM isn't supported for the current connector. + --> schema.prisma:31 +  |  + 30 |  geom_22 Geometry @db.Geometry(PolyhedralSurfaceM, 4326) + 31 |  geom_23 Geometry @db.Geometry(PolyhedralSurfaceZM, 4326) +  |  + error: Native type Geography is not supported for sqlite connector. + --> schema.prisma:32 +  |  + 31 |  geom_23 Geometry @db.Geometry(PolyhedralSurfaceZM, 4326) + 32 |  geog_00 Geometry @db.Geography(CircularString, 4326) +  |  + error: Native type Geography is not supported for sqlite connector. + --> schema.prisma:33 +  |  + 32 |  geog_00 Geometry @db.Geography(CircularString, 4326) + 33 |  geog_01 Geometry @db.Geography(CircularStringZ, 4326) +  |  + error: Native type Geography is not supported for sqlite connector. + --> schema.prisma:34 +  |  + 33 |  geog_01 Geometry @db.Geography(CircularStringZ, 4326) + 34 |  geog_02 Geometry @db.Geography(CircularStringM, 4326) +  |  + error: Native type Geography is not supported for sqlite connector. + --> schema.prisma:35 +  |  + 34 |  geog_02 Geometry @db.Geography(CircularStringM, 4326) + 35 |  geog_03 Geometry @db.Geography(CircularStringZM, 4326) +  |  + error: Native type Geography is not supported for sqlite connector. + --> schema.prisma:36 +  |  + 35 |  geog_03 Geometry @db.Geography(CircularStringZM, 4326) + 36 |  geog_04 Geometry @db.Geography(CompoundCurve, 4326) +  |  + error: Native type Geography is not supported for sqlite connector. + --> schema.prisma:37 +  |  + 36 |  geog_04 Geometry @db.Geography(CompoundCurve, 4326) + 37 |  geog_05 Geometry @db.Geography(CompoundCurveZ, 4326) +  |  + error: Native type Geography is not supported for sqlite connector. + --> schema.prisma:38 +  |  + 37 |  geog_05 Geometry @db.Geography(CompoundCurveZ, 4326) + 38 |  geog_06 Geometry @db.Geography(CompoundCurveM, 4326) +  |  + error: Native type Geography is not supported for sqlite connector. + --> schema.prisma:39 +  |  + 38 |  geog_06 Geometry @db.Geography(CompoundCurveM, 4326) + 39 |  geog_07 Geometry @db.Geography(CompoundCurveZM, 4326) +  |  + error: Native type Geography is not supported for sqlite connector. + --> schema.prisma:40 +  |  + 39 |  geog_07 Geometry @db.Geography(CompoundCurveZM, 4326) + 40 |  geog_08 Geometry @db.Geography(CurvePolygon, 4326) +  |  + error: Native type Geography is not supported for sqlite connector. + --> schema.prisma:41 +  |  + 40 |  geog_08 Geometry @db.Geography(CurvePolygon, 4326) + 41 |  geog_09 Geometry @db.Geography(CurvePolygonZ, 4326) +  |  + error: Native type Geography is not supported for sqlite connector. + --> schema.prisma:42 +  |  + 41 |  geog_09 Geometry @db.Geography(CurvePolygonZ, 4326) + 42 |  geog_10 Geometry @db.Geography(CurvePolygonM, 4326) +  |  + error: Native type Geography is not supported for sqlite connector. + --> schema.prisma:43 +  |  + 42 |  geog_10 Geometry @db.Geography(CurvePolygonM, 4326) + 43 |  geog_11 Geometry @db.Geography(CurvePolygonZM, 4326) +  |  + error: Native type Geography is not supported for sqlite connector. + --> schema.prisma:44 +  |  + 43 |  geog_11 Geometry @db.Geography(CurvePolygonZM, 4326) + 44 |  geog_12 Geometry @db.Geography(MultiCurve, 4326) +  |  + error: Native type Geography is not supported for sqlite connector. + --> schema.prisma:45 +  |  + 44 |  geog_12 Geometry @db.Geography(MultiCurve, 4326) + 45 |  geog_13 Geometry @db.Geography(MultiCurveZ, 4326) +  |  + error: Native type Geography is not supported for sqlite connector. + --> schema.prisma:46 +  |  + 45 |  geog_13 Geometry @db.Geography(MultiCurveZ, 4326) + 46 |  geog_14 Geometry @db.Geography(MultiCurveM, 4326) +  |  + error: Native type Geography is not supported for sqlite connector. + --> schema.prisma:47 +  |  + 46 |  geog_14 Geometry @db.Geography(MultiCurveM, 4326) + 47 |  geog_15 Geometry @db.Geography(MultiCurveZM, 4326) +  |  + error: Native type Geography is not supported for sqlite connector. + --> schema.prisma:48 +  |  + 47 |  geog_15 Geometry @db.Geography(MultiCurveZM, 4326) + 48 |  geog_16 Geometry @db.Geography(MultiSurface, 4326) +  |  + error: Native type Geography is not supported for sqlite connector. + --> schema.prisma:49 +  |  + 48 |  geog_16 Geometry @db.Geography(MultiSurface, 4326) + 49 |  geog_17 Geometry @db.Geography(MultiSurfaceZ, 4326) +  |  + error: Native type Geography is not supported for sqlite connector. + --> schema.prisma:50 +  |  + 49 |  geog_17 Geometry @db.Geography(MultiSurfaceZ, 4326) + 50 |  geog_18 Geometry @db.Geography(MultiSurfaceM, 4326) +  |  + error: Native type Geography is not supported for sqlite connector. + --> schema.prisma:51 +  |  + 50 |  geog_18 Geometry @db.Geography(MultiSurfaceM, 4326) + 51 |  geog_19 Geometry @db.Geography(MultiSurfaceZM, 4326) +  |  + error: Native type Geography is not supported for sqlite connector. + --> schema.prisma:52 +  |  + 51 |  geog_19 Geometry @db.Geography(MultiSurfaceZM, 4326) + 52 |  geog_20 Geometry @db.Geography(PolyhedralSurface, 4326) +  |  + error: Native type Geography is not supported for sqlite connector. + --> schema.prisma:53 +  |  + 52 |  geog_20 Geometry @db.Geography(PolyhedralSurface, 4326) + 53 |  geog_21 Geometry @db.Geography(PolyhedralSurfaceZ, 4326) +  |  + error: Native type Geography is not supported for sqlite connector. + --> schema.prisma:54 +  |  + 53 |  geog_21 Geometry @db.Geography(PolyhedralSurfaceZ, 4326) + 54 |  geog_22 Geometry @db.Geography(PolyhedralSurfaceM, 4326) +  |  + error: Native type Geography is not supported for sqlite connector. + --> schema.prisma:55 +  |  + 54 |  geog_22 Geometry @db.Geography(PolyhedralSurfaceM, 4326) + 55 |  geog_23 Geometry @db.Geography(PolyhedralSurfaceZM, 4326) +  |  + "#]]; + + expect_error(schema, &expectation); +} diff --git a/psl/psl/tests/validation/types/mongodb/invalid_json_usage_in_type.prisma b/psl/psl/tests/validation/types/mongodb/invalid_json_usage_in_type.prisma index dfd6517c2e9f..016b4035b553 100644 --- a/psl/psl/tests/validation/types/mongodb/invalid_json_usage_in_type.prisma +++ b/psl/psl/tests/validation/types/mongodb/invalid_json_usage_in_type.prisma @@ -17,37 +17,37 @@ model A { b B } -// error: Native type Json is not compatible with declared field type Int, expected field type Json. +// error: Native type Json is not compatible with declared field type Int, expected field type Json or GeoJson. // --> schema.prisma:7 //  |  //  6 | type B { //  7 |  a Int @test.Json //  |  -// error: Native type Json is not compatible with declared field type Float, expected field type Json. +// error: Native type Json is not compatible with declared field type Float, expected field type Json or GeoJson. // --> schema.prisma:8 //  |  //  7 |  a Int @test.Json //  8 |  b Float @test.Json //  |  -// error: Native type Json is not compatible with declared field type Bytes, expected field type Json. +// error: Native type Json is not compatible with declared field type Bytes, expected field type Json or GeoJson. // --> schema.prisma:9 //  |  //  8 |  b Float @test.Json //  9 |  c Bytes @test.Json //  |  -// error: Native type Json is not compatible with declared field type Boolean, expected field type Json. +// error: Native type Json is not compatible with declared field type Boolean, expected field type Json or GeoJson. // --> schema.prisma:10 //  |  //  9 |  c Bytes @test.Json // 10 |  d Boolean @test.Json //  |  -// error: Native type Json is not compatible with declared field type DateTime, expected field type Json. +// error: Native type Json is not compatible with declared field type DateTime, expected field type Json or GeoJson. // --> schema.prisma:11 //  |  // 10 |  d Boolean @test.Json // 11 |  e DateTime @test.Json //  |  -// error: Native type Json is not compatible with declared field type Decimal, expected field type Json. +// error: Native type Json is not compatible with declared field type Decimal, expected field type Json or GeoJson. // --> schema.prisma:12 //  |  // 11 |  e DateTime @test.Json diff --git a/quaint/Cargo.toml b/quaint/Cargo.toml index 52a7edf72aca..bd3451cc53a4 100644 --- a/quaint/Cargo.toml +++ b/quaint/Cargo.toml @@ -29,41 +29,16 @@ docs = [] # way to access database-specific methods when you need extra control. expose-drivers = [] -native = [ - "postgresql-native", - "mysql-native", - "mssql-native", - "sqlite-native", -] +native = ["postgresql-native", "mysql-native", "mssql-native", "sqlite-native"] all = ["native", "pooled"] -vendored-openssl = [ - "postgres-native-tls/vendored-openssl", - "mysql_async/vendored-openssl", -] +vendored-openssl = ["postgres-native-tls/vendored-openssl", "mysql_async/vendored-openssl"] -postgresql-native = [ - "postgresql", - "native-tls", - "tokio-postgres", - "postgres-types", - "postgres-native-tls", - "bytes", - "tokio", - "bit-vec", - "lru-cache", - "byteorder", -] +postgresql-native = ["postgresql", "native-tls", "tokio-postgres", "postgres-types", "postgres-native-tls", "bytes", "tokio", "bit-vec", "lru-cache", "byteorder"] postgresql = [] -mssql-native = [ - "mssql", - "tiberius", - "tokio-util", - "tokio/time", - "tokio/net", -] +mssql-native = ["mssql", "tiberius", "tokio-util", "tokio/time", "tokio/net"] mssql = [] mysql-native = ["mysql", "mysql_async", "tokio/time", "lru-cache"] @@ -100,6 +75,9 @@ mobc = { version = "0.8", optional = true } serde = { version = "1.0", optional = true } sqlformat = { version = "0.2.0", optional = true } uuid = { version = "1", features = ["v4"] } +once_cell = "1.3" +regex = "1.10.2" +geozero = { version = "0.11.0", default-features = false, features = ["with-wkb", "with-geojson"] } [dev-dependencies] once_cell = "1.3" @@ -126,8 +104,10 @@ optional = true branch = "vendored-openssl" [dependencies.rusqlite] +# git = "https://github.com/rusqlite/rusqlite" +# rev = "714ce2e17117b2d46485aa12479f8e1802b78ba0" version = "0.29" -features = ["chrono", "column_decltype"] +features = ["chrono", "column_decltype", "load_extension"] optional = true [target.'cfg(not(any(target_os = "macos", target_os = "ios")))'.dependencies.tiberius] diff --git a/quaint/src/ast.rs b/quaint/src/ast.rs index dc634423014a..ccb94b9b5b61 100644 --- a/quaint/src/ast.rs +++ b/quaint/src/ast.rs @@ -31,7 +31,7 @@ mod update; mod values; pub use column::{Column, DefaultValue, TypeDataLength, TypeFamily}; -pub use compare::{Comparable, Compare, JsonCompare, JsonType}; +pub use compare::{Comparable, Compare, GeometryCompare, GeometryType, JsonCompare, JsonType}; pub use conditions::ConditionTree; pub use conjunctive::Conjunctive; pub use cte::{CommonTableExpression, IntoCommonTableExpression}; @@ -53,5 +53,6 @@ pub use select::Select; pub use table::*; pub use union::Union; pub use update::*; +pub use values::GeometryValue; pub(crate) use values::Params; pub use values::{IntoRaw, Raw, Value, ValueType, Values}; diff --git a/quaint/src/ast/column.rs b/quaint/src/ast/column.rs index 836b4ce96527..117610a0fbe2 100644 --- a/quaint/src/ast/column.rs +++ b/quaint/src/ast/column.rs @@ -20,6 +20,8 @@ pub enum TypeFamily { Boolean, Uuid, DateTime, + Geometry(Option), + Geography(Option), Decimal(Option<(u8, u8)>), Bytes(Option), } @@ -29,9 +31,9 @@ pub enum TypeFamily { pub struct Column<'a> { pub name: Cow<'a, str>, pub(crate) table: Option>, - pub(crate) alias: Option>, + pub alias: Option>, pub(crate) default: Option>, - pub(crate) type_family: Option, + pub type_family: Option, /// Whether the column is an enum. pub(crate) is_enum: bool, /// Whether the column is a (scalar) list. diff --git a/quaint/src/ast/compare.rs b/quaint/src/ast/compare.rs index 9c7548303466..8395bb45b389 100644 --- a/quaint/src/ast/compare.rs +++ b/quaint/src/ast/compare.rs @@ -1,6 +1,6 @@ use super::ExpressionKind; use crate::ast::{Column, ConditionTree, Expression}; -use std::borrow::Cow; +use std::{borrow::Cow, fmt}; /// For modeling comparison expressions. #[derive(Debug, Clone, PartialEq)] @@ -39,6 +39,8 @@ pub enum Compare<'a> { /// All json related comparators #[cfg(any(feature = "postgresql", feature = "mysql"))] JsonCompare(JsonCompare<'a>), + /// All geometry related comparators + GeometryCompare(GeometryCompare<'a>), /// `left` @@ to_tsquery(`value`) #[cfg(feature = "postgresql")] Matches(Box>, Cow<'a, str>), @@ -53,6 +55,69 @@ pub enum Compare<'a> { All(Box>), } +#[derive(Debug, Clone, PartialEq)] +pub enum GeometryCompare<'a> { + Empty(Box>), + NotEmpty(Box>), + Valid(Box>), + NotValid(Box>), + Within(Box>, Box>), + NotWithin(Box>, Box>), + Intersects(Box>, Box>), + NotIntersects(Box>, Box>), + TypeEquals(Box>, GeometryType<'a>), + TypeNotEquals(Box>, GeometryType<'a>), +} + +#[derive(Debug, Clone, PartialEq)] +pub enum GeometryType<'a> { + Point, + LineString, + CircularString, + CompoundCurve, + Polygon, + CurvePolygon, + Triangle, + Tin, + MultiPoint, + MultiLineString, + MultiCurve, + MultiPolygon, + MultiSurface, + PolyhedralSurface, + GeometryCollection, + ColumnRef(Box>), +} + +impl<'a> From> for GeometryType<'a> { + fn from(col: Column<'a>) -> Self { + GeometryType::ColumnRef(Box::new(col)) + } +} + +impl fmt::Display for GeometryType<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Point => f.write_str("Point"), + Self::LineString => f.write_str("LineString"), + Self::CircularString => f.write_str("CircularString"), + Self::CompoundCurve => f.write_str("CompoundCurve"), + Self::Polygon => f.write_str("Polygon"), + Self::CurvePolygon => f.write_str("CurvePolygon"), + Self::Triangle => f.write_str("Triangle"), + Self::Tin => f.write_str("Tin"), + Self::MultiPoint => f.write_str("MultiPoint"), + Self::MultiLineString => f.write_str("MultiLineString"), + Self::MultiCurve => f.write_str("MultiCurve"), + Self::MultiPolygon => f.write_str("MultiPolygon"), + Self::MultiSurface => f.write_str("MultiSurface"), + Self::PolyhedralSurface => f.write_str("PolyhedralSurface"), + Self::GeometryCollection => f.write_str("GeometryCollection"), + Self::ColumnRef(_) => f.write_str(""), + } + } +} + #[derive(Debug, Clone, PartialEq)] pub enum JsonCompare<'a> { ArrayContains(Box>, Box>), @@ -737,6 +802,186 @@ pub trait Comparable<'a> { where T: Into>; + /// Tests if the geometry value is empty. + /// + /// ```rust + /// # use quaint::{ast::*, visitor::{Visitor, Sqlite}}; + /// # fn main() -> Result<(), quaint::error::Error> { + /// let query = Select::from_table("users").so_that("geom".geometry_is_empty()); + /// let (sql, _) = Sqlite::build(query)?; + /// + /// assert_eq!("SELECT `users`.* FROM `users` WHERE ST_IsEmpty(`geom`)", sql); + /// # Ok(()) + /// # } + /// ``` + fn geometry_is_empty(self) -> Compare<'a>; + + /// Tests if the geometry value is not empty. + /// + /// ```rust + /// # use quaint::{ast::*, visitor::{Visitor, Sqlite}}; + /// # fn main() -> Result<(), quaint::error::Error> { + /// let query = Select::from_table("users").so_that("geom".geometry_is_not_empty()); + /// let (sql, _) = Sqlite::build(query)?; + /// + /// assert_eq!("SELECT `users`.* FROM `users` WHERE NOT ST_IsEmpty(`geom`)", sql); + /// # Ok(()) + /// # } + /// ``` + fn geometry_is_not_empty(self) -> Compare<'a>; + + /// Tests if the geometry value is valid. + /// + /// ```rust + /// # use quaint::{ast::*, visitor::{Visitor, Sqlite}}; + /// # fn main() -> Result<(), quaint::error::Error> { + /// let query = Select::from_table("users").so_that("geom".geometry_is_valid()); + /// let (sql, _) = Sqlite::build(query)?; + /// + /// assert_eq!("SELECT `users`.* FROM `users` WHERE ST_IsValid(`geom`)", sql); + /// # Ok(()) + /// # } + /// ``` + fn geometry_is_valid(self) -> Compare<'a>; + + /// Tests if the geometry value is not valid. + /// + /// ```rust + /// # use quaint::{ast::*, visitor::{Visitor, Sqlite}}; + /// # fn main() -> Result<(), quaint::error::Error> { + /// let query = Select::from_table("users").so_that("geom".geometry_is_not_valid()); + /// let (sql, _) = Sqlite::build(query)?; + /// + /// assert_eq!("SELECT `users`.* FROM `users` WHERE NOT ST_IsValid(`geom`)", sql); + /// # Ok(()) + /// # } + /// ``` + fn geometry_is_not_valid(self) -> Compare<'a>; + + /// Tests if the left side geometry contains the right side geometry. + /// + /// ```rust + /// # use quaint::{ast::*, visitor::{Visitor, Sqlite}}; + /// # fn main() -> Result<(), quaint::error::Error> { + /// let query = Select::from_table("users").so_that("geom".geometry_within(geom_from_text("POINT(0 0)", 4326, false))); + /// let (sql, params) = Sqlite::build(query)?; + /// + /// assert_eq!("SELECT `users`.* FROM `users` WHERE ST_Within(`geom`,ST_GeomFromText(?,?))", sql); + /// + /// assert_eq!(vec![ + /// Value::from("POINT(0 0)"), + /// Value::from(4326) + /// ], params); + /// + /// # Ok(()) + /// # } + /// ``` + fn geometry_within(self, geom: T) -> Compare<'a> + where + T: Into>; + + /// Tests if the left side geometry doesn't contain the right side geometry. + /// + /// ```rust + /// # use quaint::{ast::*, visitor::{Visitor, Sqlite}}; + /// # fn main() -> Result<(), quaint::error::Error> { + /// let query = Select::from_table("users").so_that("geom".geometry_not_within(geom_from_text("POINT(0 0)", 4326, false))); + /// let (sql, params) = Sqlite::build(query)?; + /// + /// assert_eq!("SELECT `users`.* FROM `users` WHERE NOT ST_Within(`geom`,ST_GeomFromText(?,?))", sql); + /// + /// assert_eq!(vec![ + /// Value::from("POINT(0 0)"), + /// Value::from(4326) + /// ], params); + /// + /// # Ok(()) + /// # } + /// ``` + fn geometry_not_within(self, geom: T) -> Compare<'a> + where + T: Into>; + + /// Tests if the left side geometry intersects the right side geometry. + /// + /// ```rust + /// # use quaint::{ast::*, visitor::{Visitor, Sqlite}}; + /// # fn main() -> Result<(), quaint::error::Error> { + /// let query = Select::from_table("users").so_that("geom".geometry_intersects(geom_from_text("POINT(0 0)", 4326, false))); + /// let (sql, params) = Sqlite::build(query)?; + /// + /// assert_eq!("SELECT `users`.* FROM `users` WHERE ST_Intersects(`geom`,ST_GeomFromText(?,?))", sql); + /// + /// assert_eq!(vec![ + /// Value::from("POINT(0 0)"), + /// Value::from(4326) + /// ], params); + /// + /// # Ok(()) + /// # } + /// ``` + fn geometry_intersects(self, geom: T) -> Compare<'a> + where + T: Into>; + + /// Tests if the left side geometry doesn't intersect the right side geometry. + /// + /// ```rust + /// # use quaint::{ast::*, visitor::{Visitor, Sqlite}}; + /// # fn main() -> Result<(), quaint::error::Error> { + /// let query = Select::from_table("users").so_that("geom".geometry_not_intersects(geom_from_text("POINT(0 0)", 4326, false))); + /// let (sql, params) = Sqlite::build(query)?; + /// + /// assert_eq!("SELECT `users`.* FROM `users` WHERE NOT ST_Intersects(`geom`,ST_GeomFromText(?,?))", sql); + /// + /// assert_eq!(vec![ + /// Value::from("POINT(0 0)"), + /// Value::from(4326) + /// ], params); + /// + /// # Ok(()) + /// # } + /// ``` + fn geometry_not_intersects(self, geom: T) -> Compare<'a> + where + T: Into>; + + /// Tests if the geometry value is of a certain type. + /// + /// ```rust + /// # use quaint::{ast::*, visitor::{Visitor, Sqlite}}; + /// # fn main() -> Result<(), quaint::error::Error> { + /// let query = Select::from_table("users").so_that("geom".geometry_type_equals(GeometryType::Point)); + /// let (sql, params) = Sqlite::build(query)?; + /// + /// assert_eq!("SELECT `users`.* FROM `users` WHERE ST_GeometryType(`geom`) = ?", sql); + /// + /// assert_eq!(vec![Value::from("POINT")], params); + /// # Ok(()) + /// # } + /// ``` + fn geometry_type_equals(self, geom_type: T) -> Compare<'a> + where + T: Into>; + + /// Tests if the geometry value is not of a certain type. + /// + /// ```rust + /// # use quaint::{ast::*, visitor::{Visitor, Sqlite}}; + /// # fn main() -> Result<(), quaint::error::Error> { + /// let query = Select::from_table("users").so_that("geom".geometry_type_not_equals(GeometryType::Point)); + /// let (sql, params) = Sqlite::build(query)?; + /// + /// assert_eq!("SELECT `users`.* FROM `users` WHERE ST_GeometryType(`geom`) != ?", sql); + /// + /// assert_eq!(vec![Value::from("POINT")], params); + /// # Ok(()) + /// # } + /// ``` + fn geometry_type_not_equals(self, geom_type: T) -> Compare<'a> + where + T: Into>; + /// Tests if a full-text search matches a certain query. Use it in combination with the `text_search()` function /// /// ```rust @@ -1065,6 +1310,88 @@ where val.json_type_not_equals(json_type) } + #[allow(clippy::wrong_self_convention)] + fn geometry_is_empty(self) -> Compare<'a> { + let col: Column<'a> = self.into(); + let val: Expression<'a> = col.into(); + val.geometry_is_empty() + } + + #[allow(clippy::wrong_self_convention)] + fn geometry_is_not_empty(self) -> Compare<'a> { + let col: Column<'a> = self.into(); + let val: Expression<'a> = col.into(); + val.geometry_is_not_empty() + } + + #[allow(clippy::wrong_self_convention)] + fn geometry_is_valid(self) -> Compare<'a> { + let col: Column<'a> = self.into(); + let val: Expression<'a> = col.into(); + val.geometry_is_valid() + } + + #[allow(clippy::wrong_self_convention)] + fn geometry_is_not_valid(self) -> Compare<'a> { + let col: Column<'a> = self.into(); + let val: Expression<'a> = col.into(); + val.geometry_is_not_valid() + } + + fn geometry_within(self, geom: T) -> Compare<'a> + where + T: Into>, + { + let col: Column<'a> = self.into(); + let val: Expression<'a> = col.into(); + val.geometry_within(geom) + } + + fn geometry_not_within(self, geom: T) -> Compare<'a> + where + T: Into>, + { + let col: Column<'a> = self.into(); + let val: Expression<'a> = col.into(); + val.geometry_not_within(geom) + } + + fn geometry_intersects(self, geom: T) -> Compare<'a> + where + T: Into>, + { + let col: Column<'a> = self.into(); + let val: Expression<'a> = col.into(); + val.geometry_intersects(geom) + } + + fn geometry_not_intersects(self, geom: T) -> Compare<'a> + where + T: Into>, + { + let col: Column<'a> = self.into(); + let val: Expression<'a> = col.into(); + val.geometry_not_intersects(geom) + } + + fn geometry_type_equals(self, geom_type: T) -> Compare<'a> + where + T: Into>, + { + let col: Column<'a> = self.into(); + let val: Expression<'a> = col.into(); + val.geometry_type_equals(geom_type) + } + + fn geometry_type_not_equals(self, geom_type: T) -> Compare<'a> + where + T: Into>, + { + let col: Column<'a> = self.into(); + let val: Expression<'a> = col.into(); + val.geometry_type_not_equals(geom_type) + } + #[cfg(feature = "postgresql")] fn matches(self, query: T) -> Compare<'a> where diff --git a/quaint/src/ast/expression.rs b/quaint/src/ast/expression.rs index ea4c32a4fb61..4c5e5200605b 100644 --- a/quaint/src/ast/expression.rs +++ b/quaint/src/ast/expression.rs @@ -1,3 +1,4 @@ +use super::compare::{GeometryCompare, GeometryType}; #[cfg(any(feature = "postgresql", feature = "mysql"))] use super::compare::{JsonCompare, JsonType}; use crate::ast::*; @@ -98,6 +99,11 @@ impl<'a> Expression<'a> { self.kind.is_xml_value() } + #[allow(dead_code)] + pub(crate) fn is_geometry_expr(&self) -> bool { + self.kind.is_geometry_expr() + } + #[allow(dead_code)] pub fn is_asterisk(&self) -> bool { matches!(self.kind, ExpressionKind::Asterisk(_)) @@ -234,6 +240,32 @@ impl<'a> ExpressionKind<'a> { _ => false, } } + pub(crate) fn is_geometry_expr(&self) -> bool { + match self { + Self::Parameterized(Value { + typed: ValueType::Geometry(_), + .. + }) => true, + Self::Parameterized(Value { + typed: ValueType::Geography(_), + .. + }) => true, + Self::RawValue(Raw(Value { + typed: ValueType::Geometry(_), + .. + })) => true, + Self::RawValue(Raw(Value { + typed: ValueType::Geography(_), + .. + })) => true, + Self::Column(c) if matches!(c.type_family, Some(TypeFamily::Geography(_) | TypeFamily::Geometry(_))) => { + true + } + Self::Function(f) => f.returns_geometry(), + Self::Value(expr) => expr.is_geometry_expr(), + _ => false, + } + } } /// A quick alias to create an asterisk to a table. @@ -507,6 +539,64 @@ impl<'a> Comparable<'a> for Expression<'a> { Compare::JsonCompare(JsonCompare::TypeNotEquals(Box::new(self), json_type.into())) } + fn geometry_is_empty(self) -> Compare<'a> { + Compare::GeometryCompare(GeometryCompare::Empty(Box::new(self))) + } + + fn geometry_is_not_empty(self) -> Compare<'a> { + Compare::GeometryCompare(GeometryCompare::NotEmpty(Box::new(self))) + } + + fn geometry_is_valid(self) -> Compare<'a> { + Compare::GeometryCompare(GeometryCompare::Valid(Box::new(self))) + } + + fn geometry_is_not_valid(self) -> Compare<'a> { + Compare::GeometryCompare(GeometryCompare::NotValid(Box::new(self))) + } + + fn geometry_type_equals(self, geometry_type: T) -> Compare<'a> + where + T: Into>, + { + Compare::GeometryCompare(GeometryCompare::TypeEquals(Box::new(self), geometry_type.into())) + } + + fn geometry_type_not_equals(self, geometry_type: T) -> Compare<'a> + where + T: Into>, + { + Compare::GeometryCompare(GeometryCompare::TypeNotEquals(Box::new(self), geometry_type.into())) + } + + fn geometry_within(self, geom: T) -> Compare<'a> + where + T: Into>, + { + Compare::GeometryCompare(GeometryCompare::Within(Box::new(self), Box::new(geom.into()))) + } + + fn geometry_not_within(self, geom: T) -> Compare<'a> + where + T: Into>, + { + Compare::GeometryCompare(GeometryCompare::NotWithin(Box::new(self), Box::new(geom.into()))) + } + + fn geometry_intersects(self, geom: T) -> Compare<'a> + where + T: Into>, + { + Compare::GeometryCompare(GeometryCompare::Intersects(Box::new(self), Box::new(geom.into()))) + } + + fn geometry_not_intersects(self, geom: T) -> Compare<'a> + where + T: Into>, + { + Compare::GeometryCompare(GeometryCompare::NotIntersects(Box::new(self), Box::new(geom.into()))) + } + #[cfg(feature = "postgresql")] fn matches(self, query: T) -> Compare<'a> where diff --git a/quaint/src/ast/function.rs b/quaint/src/ast/function.rs index 5b6373795485..753ab26e139b 100644 --- a/quaint/src/ast/function.rs +++ b/quaint/src/ast/function.rs @@ -20,6 +20,9 @@ mod search; mod sum; mod upper; +mod geom_as_text; +mod geom_from_text; + #[cfg(feature = "mysql")] mod uuid; @@ -45,6 +48,9 @@ pub use search::*; pub use sum::*; pub use upper::*; +pub use geom_as_text::*; +pub use geom_from_text::*; + #[cfg(feature = "mysql")] pub use self::uuid::*; @@ -72,6 +78,12 @@ impl<'a> Function<'a> { _ => false, } } + pub fn returns_geometry(&self) -> bool { + match self.typ_ { + FunctionType::GeomFromText(_) => true, + _ => false, + } + } } /// A database function type @@ -108,6 +120,8 @@ pub(crate) enum FunctionType<'a> { UuidToBinSwapped, #[cfg(feature = "mysql")] Uuid, + GeomAsText(GeomAsText<'a>), + GeomFromText(GeomFromText<'a>), } impl<'a> Aliasable<'a> for Function<'a> { @@ -156,3 +170,5 @@ function!( Coalesce, Concat ); + +function!(GeomAsText, GeomFromText); diff --git a/quaint/src/ast/function/geom_as_text.rs b/quaint/src/ast/function/geom_as_text.rs new file mode 100644 index 000000000000..8c189e75f122 --- /dev/null +++ b/quaint/src/ast/function/geom_as_text.rs @@ -0,0 +1,31 @@ +use super::Function; +use crate::ast::Expression; + +/// A represention of the `ST_AsText` function in the database. +#[derive(Debug, Clone, PartialEq)] +pub struct GeomAsText<'a> { + pub(crate) expression: Box>, +} + +/// Read the geometry expression into a EWKT string. +/// +/// ```rust +/// # use quaint::{ast::*, visitor::{Visitor, Sqlite}}; +/// # fn main() -> Result<(), quaint::error::Error> { +/// let query = Select::from_table("users").value(geom_as_text(Column::from("location"))); +/// let (sql, _) = Sqlite::build(query)?; +/// +/// assert_eq!("SELECT AsEWKT(`location`) FROM `users`", sql); +/// # Ok(()) +/// # } +/// ``` +pub fn geom_as_text<'a, E>(expression: E) -> Function<'a> +where + E: Into>, +{ + let fun = GeomAsText { + expression: Box::new(expression.into()), + }; + + fun.into() +} diff --git a/quaint/src/ast/function/geom_from_text.rs b/quaint/src/ast/function/geom_from_text.rs new file mode 100644 index 000000000000..a8b4481f9236 --- /dev/null +++ b/quaint/src/ast/function/geom_from_text.rs @@ -0,0 +1,41 @@ +use super::Function; +use crate::ast::Expression; + +/// A represention of the `ST_AsText` function in the database. +#[derive(Debug, Clone, PartialEq)] +pub struct GeomFromText<'a> { + pub(crate) wkt_expression: Box>, + pub(crate) srid_expression: Box>, + pub(crate) geography: bool, +} + +/// Write a WKT geometry value using built-in database conversion. +/// +/// ```rust +/// # use quaint::{ast::*, visitor::{Visitor, Sqlite}}; +/// # fn main() -> Result<(), quaint::error::Error> { +/// let query = Insert::single_into("users").value("location", geom_from_text("POINT(0 0)", 4326, false)); +/// let (sql, params) = Sqlite::build(query)?; +/// +/// assert_eq!("INSERT INTO `users` (`location`) VALUES (ST_GeomFromText(?,?))", sql); +/// +/// assert_eq!(vec![ +/// Value::from("POINT(0 0)"), +/// Value::from(4326) +/// ], params); +/// # Ok(()) +/// # } +/// ``` +pub fn geom_from_text<'a, G, S>(wkt_expression: G, srid_expression: S, geography: bool) -> Function<'a> +where + G: Into>, + S: Into>, +{ + let fun = GeomFromText { + wkt_expression: Box::new(wkt_expression.into()), + srid_expression: Box::new(srid_expression.into()), + geography, + }; + + fun.into() +} diff --git a/quaint/src/ast/row.rs b/quaint/src/ast/row.rs index e556cee966af..f29a58d9897f 100644 --- a/quaint/src/ast/row.rs +++ b/quaint/src/ast/row.rs @@ -1,3 +1,4 @@ +use super::compare::GeometryType; #[cfg(any(feature = "postgresql", feature = "mysql"))] use super::compare::JsonType; use crate::ast::{Comparable, Compare, Expression}; @@ -363,6 +364,80 @@ impl<'a> Comparable<'a> for Row<'a> { value.json_type_not_equals(json_type) } + #[allow(clippy::wrong_self_convention)] + fn geometry_is_empty(self) -> Compare<'a> { + let value: Expression<'a> = self.into(); + value.geometry_is_empty() + } + + #[allow(clippy::wrong_self_convention)] + fn geometry_is_not_empty(self) -> Compare<'a> { + let value: Expression<'a> = self.into(); + value.geometry_is_not_empty() + } + + #[allow(clippy::wrong_self_convention)] + fn geometry_is_valid(self) -> Compare<'a> { + let value: Expression<'a> = self.into(); + value.geometry_is_valid() + } + + #[allow(clippy::wrong_self_convention)] + fn geometry_is_not_valid(self) -> Compare<'a> { + let value: Expression<'a> = self.into(); + value.geometry_is_not_valid() + } + + fn geometry_within(self, geom: T) -> Compare<'a> + where + T: Into>, + { + let value: Expression<'a> = self.into(); + value.geometry_within(geom) + } + + fn geometry_not_within(self, geom: T) -> Compare<'a> + where + T: Into>, + { + let value: Expression<'a> = self.into(); + value.geometry_not_within(geom) + } + + fn geometry_intersects(self, geom: T) -> Compare<'a> + where + T: Into>, + { + let value: Expression<'a> = self.into(); + value.geometry_intersects(geom) + } + + fn geometry_not_intersects(self, geom: T) -> Compare<'a> + where + T: Into>, + { + let value: Expression<'a> = self.into(); + value.geometry_not_intersects(geom) + } + + fn geometry_type_equals(self, geometry_type: T) -> Compare<'a> + where + T: Into>, + { + let value: Expression<'a> = self.into(); + + value.geometry_type_equals(geometry_type) + } + + fn geometry_type_not_equals(self, geometry_type: T) -> Compare<'a> + where + T: Into>, + { + let value: Expression<'a> = self.into(); + + value.geometry_type_not_equals(geometry_type) + } + #[cfg(feature = "postgresql")] fn matches(self, query: T) -> Compare<'a> where diff --git a/quaint/src/ast/values.rs b/quaint/src/ast/values.rs index a1bf4f41a26d..ad1577bed7cd 100644 --- a/quaint/src/ast/values.rs +++ b/quaint/src/ast/values.rs @@ -4,7 +4,7 @@ use crate::error::{Error, ErrorKind}; use bigdecimal::{BigDecimal, FromPrimitive, ToPrimitive}; use chrono::{DateTime, NaiveDate, NaiveTime, Utc}; use serde_json::{Number, Value as JsonValue}; -use std::fmt::Display; +use std::fmt::{Display, Formatter}; use std::{ borrow::{Borrow, Cow}, convert::TryFrom, @@ -13,6 +13,9 @@ use std::{ }; use uuid::Uuid; +use once_cell::sync::Lazy; +use regex::Regex; + /// A value written to the query as-is without parameterization. #[derive(Debug, Clone, PartialEq)] pub struct Raw<'a>(pub(crate) Value<'a>); @@ -33,6 +36,43 @@ where } } +#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] +pub struct GeometryValue { + pub wkt: String, + pub srid: i32, +} + +impl Display for GeometryValue { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self.srid { + 0 => (), + srid => write!(f, "SRID={};", srid)?, + } + f.write_str(&self.wkt) + } +} + +impl FromStr for GeometryValue { + type Err = String; + + fn from_str(s: &str) -> Result { + static EWKT_REGEX: Lazy = + Lazy::new(|| Regex::new(r"^(SRID=(?P\d+);)?(?P.+)$").unwrap()); + EWKT_REGEX + .captures(s) + .map(|capture| { + let srid = match capture.name("srid").map(|v| v.as_str().parse::()) { + None => Ok(0), + Some(Ok(srid)) => Ok(srid), + Some(Err(_)) => Err("Invalid SRID"), + }?; + let wkt = capture.name("geometry").map(|v| v.as_str()).unwrap().to_string(); + Ok(GeometryValue { srid, wkt }) + }) + .ok_or("Invalid EWKT".to_string())? + } +} + /// A native-column type, i.e. the connector-specific type of the column. #[derive(Debug, Clone, PartialEq)] pub struct NativeColumnType<'a>(Cow<'a, str>); @@ -209,6 +249,22 @@ impl<'a> Value<'a> { ValueType::xml(value).into_value() } + /// Creates a new geometry value. + pub fn geometry(value: T) -> Self + where + T: Into, + { + ValueType::geometry(value).into_value() + } + + /// Creates a new geography value. + pub fn geography(value: T) -> Self + where + T: Into, + { + ValueType::geography(value).into_value() + } + /// `true` if the `Value` is null. pub fn is_null(&self) -> bool { self.typed.is_null() @@ -472,6 +528,10 @@ impl<'a> Value<'a> { pub fn null_time() -> Self { ValueType::Time(None).into() } + + pub fn null_geometry() -> Self { + ValueType::Time(None).into() + } } impl<'a> Display for Value<'a> { @@ -530,6 +590,10 @@ pub enum ValueType<'a> { Numeric(Option), /// A JSON value. Json(Option), + /// A Geometry value. + Geometry(Option), + /// A Geography value. + Geography(Option), /// A XML value. Xml(Option>), /// An UUID value. @@ -606,6 +670,8 @@ impl<'a> fmt::Display for ValueType<'a> { ValueType::DateTime(val) => val.map(|v| write!(f, "\"{v}\"")), ValueType::Date(val) => val.map(|v| write!(f, "\"{v}\"")), ValueType::Time(val) => val.map(|v| write!(f, "\"{v}\"")), + ValueType::Geometry(val) => val.as_ref().map(|v| write!(f, "\"{v}\"")), + ValueType::Geography(val) => val.as_ref().map(|v| write!(f, "\"{v}\"")), }; match res { @@ -664,6 +730,8 @@ impl<'a> From> for serde_json::Value { ValueType::DateTime(dt) => dt.map(|dt| serde_json::Value::String(dt.to_rfc3339())), ValueType::Date(date) => date.map(|date| serde_json::Value::String(format!("{date}"))), ValueType::Time(time) => time.map(|time| serde_json::Value::String(format!("{time}"))), + ValueType::Geometry(g) => g.map(|g| serde_json::Value::String(g.to_string())), + ValueType::Geography(g) => g.map(|g| serde_json::Value::String(g.to_string())), }; match res { @@ -810,6 +878,22 @@ impl<'a> ValueType<'a> { Self::Json(Some(value)) } + /// Creates a new geometry value. + pub fn geometry(value: T) -> Self + where + T: Into, + { + Self::Geometry(Some(value.into())) + } + + /// Creates a new geometry value. + pub fn geography(value: T) -> Self + where + T: Into, + { + Self::Geography(Some(value.into())) + } + /// Creates a new XML value. pub(crate) fn xml(value: T) -> Self where @@ -839,6 +923,8 @@ impl<'a> ValueType<'a> { Self::Date(d) => d.is_none(), Self::Time(t) => t.is_none(), Self::Json(json) => json.is_none(), + Self::Geometry(geom) => geom.is_none(), + Self::Geography(geom) => geom.is_none(), } } diff --git a/quaint/src/connector/mssql/conversion.rs b/quaint/src/connector/mssql/conversion.rs new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/quaint/src/connector/mssql/native/conversion.rs b/quaint/src/connector/mssql/native/conversion.rs index 870654ad5de3..e41cb5f73357 100644 --- a/quaint/src/connector/mssql/native/conversion.rs +++ b/quaint/src/connector/mssql/native/conversion.rs @@ -26,6 +26,8 @@ impl<'a> IntoSql<'a> for &'a Value<'a> { ValueType::DateTime(val) => val.into_sql(), ValueType::Date(val) => val.into_sql(), ValueType::Time(val) => val.into_sql(), + ValueType::Geometry(_) => panic!("Cannot handle raw Geometry"), + ValueType::Geography(_) => panic!("Cannot handle raw Geography"), } } } diff --git a/quaint/src/connector/mysql/native/conversion.rs b/quaint/src/connector/mysql/native/conversion.rs index 659cc0790c07..85ebeed7fd47 100644 --- a/quaint/src/connector/mysql/native/conversion.rs +++ b/quaint/src/connector/mysql/native/conversion.rs @@ -4,11 +4,12 @@ use crate::{ error::{Error, ErrorKind}, }; use chrono::{DateTime, Datelike, NaiveDate, NaiveDateTime, NaiveTime, Timelike, Utc}; +use geozero::{wkb::MySQLWkb, wkt::WktStr, ToWkb, ToWkt}; use mysql_async::{ self as my, consts::{ColumnFlags, ColumnType}, }; -use std::convert::TryFrom; +use std::{convert::TryFrom, vec}; pub fn conv_params(params: &[Value<'_>]) -> crate::Result { if params.is_empty() { @@ -68,6 +69,13 @@ pub fn conv_params(params: &[Value<'_>]) -> crate::Result { dt.timestamp_subsec_micros(), ) }), + ValueType::Geometry(g) | ValueType::Geography(g) => g.as_ref().map(|g| { + // TODO@geometry: Improve WKB serialization error handling + WktStr(&g.wkt) + .to_mysql_wkb(Some(g.srid)) + .map(my::Value::Bytes) + .unwrap_or_else(|_| panic!("Couldn't convert value `{g}` into EWKB.")) + }), }; match res { @@ -193,6 +201,10 @@ impl TypeIdentifier for my::Column { self.column_type() == ColumnType::MYSQL_TYPE_JSON } + fn is_geometry(&self) -> bool { + self.column_type() == ColumnType::MYSQL_TYPE_GEOMETRY + } + fn is_enum(&self) -> bool { self.flags() == ColumnFlags::ENUM_FLAG || self.column_type() == ColumnType::MYSQL_TYPE_ENUM } @@ -255,6 +267,14 @@ impl TakeRow for my::Row { [0] => Value::boolean(false), _ => Value::boolean(true), }, + my::Value::Bytes(b) if column.is_geometry() => { + MySQLWkb(b).to_ewkt(None).map(Value::text).map_err(|_| { + let msg = "Could not convert geometry blob to Ewkt"; + let kind = ErrorKind::conversion(msg); + + Error::builder(kind).build() + })? + } // https://dev.mysql.com/doc/internals/en/character-set.html my::Value::Bytes(b) if column.character_set() == 63 => Value::bytes(b), my::Value::Bytes(s) => Value::text(String::from_utf8(s)?), @@ -316,6 +336,7 @@ impl TakeRow for my::Row { t if t.is_time() => Value::null_time(), t if t.is_date() => Value::null_date(), t if t.is_json() => Value::null_json(), + t if t.is_geometry() => Value::null_geometry(), typ => { let msg = format!("Value of type {typ:?} is not supported with the current configuration"); diff --git a/quaint/src/connector/postgres/native/conversion.rs b/quaint/src/connector/postgres/native/conversion.rs index efe4debd9b94..21ed6b2407de 100644 --- a/quaint/src/connector/postgres/native/conversion.rs +++ b/quaint/src/connector/postgres/native/conversion.rs @@ -12,6 +12,7 @@ use bytes::BytesMut; use chrono::{DateTime, NaiveDateTime, Utc}; pub(crate) use decimal::DecimalWrapper; +use geozero::{wkb::Ewkb, ToWkt}; use postgres_types::{FromSql, ToSql, WrongType}; use std::{convert::TryFrom, error::Error as StdError}; use tokio_postgres::{ @@ -54,6 +55,8 @@ pub(crate) fn params_to_types(params: &[Value<'_>]) -> Vec { ValueType::DateTime(_) => PostgresType::TIMESTAMPTZ, ValueType::Date(_) => PostgresType::TIMESTAMP, ValueType::Time(_) => PostgresType::TIME, + ValueType::Geometry(_) => PostgresType::BYTEA, + ValueType::Geography(_) => PostgresType::BYTEA, ValueType::Array(ref arr) => { let arr = arr.as_ref().unwrap(); @@ -90,6 +93,8 @@ pub(crate) fn params_to_types(params: &[Value<'_>]) -> Vec { ValueType::DateTime(_) => PostgresType::TIMESTAMPTZ_ARRAY, ValueType::Date(_) => PostgresType::TIMESTAMP_ARRAY, ValueType::Time(_) => PostgresType::TIME_ARRAY, + ValueType::Geometry(_) => PostgresType::BYTEA, + ValueType::Geography(_) => PostgresType::BYTEA, // In the case of nested arrays, we let PG infer the type ValueType::Array(_) => PostgresType::UNKNOWN, } @@ -99,6 +104,18 @@ pub(crate) fn params_to_types(params: &[Value<'_>]) -> Vec { .collect() } +struct EwktString(pub String); + +impl<'a> FromSql<'a> for EwktString { + fn from_sql(_ty: &PostgresType, raw: &'a [u8]) -> Result> { + Ok(Ewkb(raw.to_owned()).to_ewkt(None).map(EwktString)?) + } + + fn accepts(ty: &PostgresType) -> bool { + matches!(ty.name(), "geometry" | "geography") + } +} + struct XmlString(pub String); impl<'a> FromSql<'a> for XmlString { @@ -502,6 +519,12 @@ impl GetRow for PostgresRow { } None => Value::null_array(), }, + ref x if matches!(x.name(), "geometry" | "geography") => { + match row.try_get::<_, Option>(i)? { + Some(ewkt) => Value::text(ewkt.0), + None => Value::null_text(), + } + } ref x => match x.kind() { Kind::Enum => match row.try_get(i)? { Some(val) => { @@ -854,6 +877,8 @@ impl<'a> ToSql for Value<'a> { Ok(result) }), (ValueType::DateTime(value), _) => value.map(|value| value.naive_utc().to_sql(ty, out)), + (ValueType::Geometry(_), _) => panic!("Cannot handle raw Geometry"), + (ValueType::Geography(_), _) => panic!("Cannot handle raw Geography"), }; match res { diff --git a/quaint/src/connector/sqlite/native/conversion.rs b/quaint/src/connector/sqlite/native/conversion.rs index fced37abca4c..84d0b63b6c2a 100644 --- a/quaint/src/connector/sqlite/native/conversion.rs +++ b/quaint/src/connector/sqlite/native/conversion.rs @@ -9,6 +9,7 @@ use crate::{ error::{Error, ErrorKind}, }; +use geozero::{wkb::SpatiaLiteWkb, ToWkt}; use rusqlite::{ types::{Null, ToSql, ToSqlOutput, ValueRef}, Column, Error as RusqlError, Row as SqliteRow, Rows as SqliteRows, @@ -118,6 +119,20 @@ impl TypeIdentifier for Column<'_> { matches!(self.decl_type(), Some("BOOLEAN") | Some("boolean")) } + fn is_geometry(&self) -> bool { + match self.decl_type() { + Some(n) if n.eq_ignore_ascii_case("GEOMETRY") => true, + Some(n) if n.eq_ignore_ascii_case("POINT") => true, + Some(n) if n.eq_ignore_ascii_case("LINESTRING") => true, + Some(n) if n.eq_ignore_ascii_case("POLYGON") => true, + Some(n) if n.eq_ignore_ascii_case("MULTIPOINT") => true, + Some(n) if n.eq_ignore_ascii_case("MULTILINESTRING") => true, + Some(n) if n.eq_ignore_ascii_case("MULTIPOLYGON") => true, + Some(n) if n.eq_ignore_ascii_case("GEOMETRYCOLLECTION") => true, + _ => false, + } + } + fn is_json(&self) -> bool { false } @@ -148,6 +163,7 @@ impl<'a> GetRow for SqliteRow<'a> { c if c.is_datetime() => Value::null_datetime(), c if c.is_date() => Value::null_date(), c if c.is_bool() => Value::null_boolean(), + c if c.is_geometry() => Value::null_geometry(), c => match c.decl_type() { Some(n) => { let msg = format!("Value {n} not supported"); @@ -221,6 +237,15 @@ impl<'a> GetRow for SqliteRow<'a> { }) })? } + ValueRef::Blob(bytes) if column.is_geometry() => SpatiaLiteWkb(bytes.to_vec()) + .to_ewkt(None) + .map(Value::text) + .map_err(|_| { + let builder = Error::builder(ErrorKind::ConversionError( + "Failed to read contents of SQLite geometry column as WKT".into(), + )); + builder.build() + })?, ValueRef::Text(bytes) => Value::text(String::from_utf8(bytes.to_vec())?), ValueRef::Blob(bytes) => Value::bytes(bytes.to_owned()), }; @@ -285,6 +310,8 @@ impl<'a> ToSql for Value<'a> { date.and_hms_opt(time.hour(), time.minute(), time.second()) }) .map(|dt| ToSqlOutput::from(dt.timestamp_millis())), + ValueType::Geometry(_) => panic!("Cannot handle raw Geometry"), + ValueType::Geography(_) => panic!("Cannot handle raw Geography"), }; match value { diff --git a/quaint/src/connector/sqlite/native/mod.rs b/quaint/src/connector/sqlite/native/mod.rs index 3bf0c46a7db5..9220fe75b517 100644 --- a/quaint/src/connector/sqlite/native/mod.rs +++ b/quaint/src/connector/sqlite/native/mod.rs @@ -7,7 +7,7 @@ mod error; use crate::connector::sqlite::params::SqliteParams; use crate::connector::IsolationLevel; -pub use rusqlite::{params_from_iter, version as sqlite_version}; +pub use rusqlite::{params_from_iter, version as sqlite_version, LoadExtensionGuard}; use crate::{ ast::{Query, Value}, @@ -28,6 +28,18 @@ pub struct Sqlite { pub(crate) client: Mutex, } +fn load_spatialite(conn: &rusqlite::Connection) -> crate::Result<()> { + // Loading Spatialite here isn't ideal, but needed because it has to be + // done for every new pooled connection..? + if let Ok(spatialite_path) = std::env::var("SPATIALITE_PATH") { + unsafe { + let _guard = LoadExtensionGuard::new(conn)?; + conn.load_extension(spatialite_path, None)?; + } + } + Ok(()) +} + impl TryFrom<&str> for Sqlite { type Error = Error; @@ -36,6 +48,7 @@ impl TryFrom<&str> for Sqlite { let file_path = params.file_path; let conn = rusqlite::Connection::open(file_path.as_str())?; + load_spatialite(&conn)?; if let Some(timeout) = params.socket_timeout { conn.busy_timeout(timeout)?; @@ -55,6 +68,7 @@ impl Sqlite { /// Open a new SQLite database in memory. pub fn new_in_memory() -> crate::Result { let client = rusqlite::Connection::open_in_memory()?; + load_spatialite(&client)?; Ok(Sqlite { client: Mutex::new(client), diff --git a/quaint/src/connector/type_identifier.rs b/quaint/src/connector/type_identifier.rs index 9fcc46f61c1c..d8ef1d39f5d2 100644 --- a/quaint/src/connector/type_identifier.rs +++ b/quaint/src/connector/type_identifier.rs @@ -11,6 +11,7 @@ pub(crate) trait TypeIdentifier { fn is_bytes(&self) -> bool; fn is_bool(&self) -> bool; fn is_json(&self) -> bool; + fn is_geometry(&self) -> bool; fn is_enum(&self) -> bool; fn is_null(&self) -> bool; } diff --git a/quaint/src/serde.rs b/quaint/src/serde.rs new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/quaint/src/visitor.rs b/quaint/src/visitor.rs index c205b49dd279..6b4e823ebcc3 100644 --- a/quaint/src/visitor.rs +++ b/quaint/src/visitor.rs @@ -139,6 +139,48 @@ pub trait Visitor<'a> { #[cfg(any(feature = "postgresql", feature = "mysql"))] fn visit_json_unquote(&mut self, json_unquote: JsonUnquote<'a>) -> Result; + fn visit_geom_as_text(&mut self, geom: GeomAsText<'a>) -> Result; + + fn visit_geom_from_text(&mut self, geom: GeomFromText<'a>) -> Result; + + fn visit_geometry_type_equals(&mut self, left: Expression<'a>, right: GeometryType<'a>, not: bool) -> Result; + + fn visit_geometry_empty(&mut self, left: Expression<'a>, not: bool) -> Result { + if not { + self.write("NOT ")?; + } + self.surround_with("ST_IsEmpty(", ")", |s| s.visit_expression(left)) + } + + fn visit_geometry_valid(&mut self, left: Expression<'a>, not: bool) -> Result { + if not { + self.write("NOT ")?; + } + self.surround_with("ST_IsValid(", ")", |s| s.visit_expression(left)) + } + + fn visit_geometry_within(&mut self, left: Expression<'a>, right: Expression<'a>, not: bool) -> Result { + if not { + self.write("NOT ")?; + } + self.surround_with("ST_Within(", ")", |s| { + s.visit_expression(left)?; + s.write(",")?; + s.visit_expression(right) + }) + } + + fn visit_geometry_intersects(&mut self, left: Expression<'a>, right: Expression<'a>, not: bool) -> Result { + if not { + self.write("NOT ")?; + } + self.surround_with("ST_Intersects(", ")", |s| { + s.visit_expression(left)?; + s.write(",")?; + s.visit_expression(right) + }) + } + #[cfg(any(feature = "postgresql", feature = "mysql"))] fn visit_text_search(&mut self, text_search: TextSearch<'a>) -> Result; @@ -175,6 +217,9 @@ pub trait Visitor<'a> { match value.typed { ValueType::Enum(Some(variant), name) => self.visit_parameterized_enum(variant, name), ValueType::EnumArray(Some(variants), name) => self.visit_parameterized_enum_array(variants, name), + ValueType::Geometry(Some(geom)) => self.visit_function(geom_from_text(geom.wkt, geom.srid, false)), + ValueType::Geography(Some(geom)) => self.visit_function(geom_from_text(geom.wkt, geom.srid, true)), + ValueType::Geometry(None) | ValueType::Geography(None) => self.write("NULL"), _ => { self.add_parameter(value); self.parameter_substitution() @@ -950,6 +995,22 @@ pub trait Visitor<'a> { JsonCompare::TypeEquals(left, json_type) => self.visit_json_type_equals(*left, json_type, false), JsonCompare::TypeNotEquals(left, json_type) => self.visit_json_type_equals(*left, json_type, true), }, + Compare::GeometryCompare(geom_compare) => match geom_compare { + GeometryCompare::Empty(left) => self.visit_geometry_empty(*left, false), + GeometryCompare::NotEmpty(left) => self.visit_geometry_empty(*left, true), + GeometryCompare::Valid(left) => self.visit_geometry_valid(*left, false), + GeometryCompare::NotValid(left) => self.visit_geometry_valid(*left, true), + GeometryCompare::Within(left, right) => self.visit_geometry_within(*left, *right, false), + GeometryCompare::NotWithin(left, right) => self.visit_geometry_within(*left, *right, true), + GeometryCompare::Intersects(left, right) => self.visit_geometry_intersects(*left, *right, false), + GeometryCompare::NotIntersects(left, right) => self.visit_geometry_intersects(*left, *right, true), + GeometryCompare::TypeEquals(left, geom_type) => { + self.visit_geometry_type_equals(*left, geom_type, false) + } + GeometryCompare::TypeNotEquals(left, geom_type) => { + self.visit_geometry_type_equals(*left, geom_type, true) + } + }, #[cfg(feature = "postgresql")] Compare::Matches(left, right) => self.visit_matches(*left, right, false), #[cfg(feature = "postgresql")] @@ -1106,6 +1167,12 @@ pub trait Visitor<'a> { FunctionType::Concat(concat) => { self.visit_concat(concat)?; } + FunctionType::GeomAsText(geom) => { + self.visit_geom_as_text(geom)?; + } + FunctionType::GeomFromText(geom) => { + self.visit_geom_from_text(geom)?; + } }; if let Some(alias) = fun.alias { diff --git a/quaint/src/visitor/mssql.rs b/quaint/src/visitor/mssql.rs index bf1550b96c31..ca2d1e5eed55 100644 --- a/quaint/src/visitor/mssql.rs +++ b/quaint/src/visitor/mssql.rs @@ -2,10 +2,7 @@ use super::Visitor; #[cfg(any(feature = "postgresql", feature = "mysql"))] use crate::prelude::{JsonExtract, JsonType, JsonUnquote}; use crate::{ - ast::{ - Column, Comparable, Expression, ExpressionKind, Insert, IntoRaw, Join, JoinData, Joinable, Merge, OnConflict, - Order, Ordering, Row, Table, TypeDataLength, TypeFamily, Values, - }, + ast::*, error::{Error, ErrorKind}, prelude::{Aliasable, Average, Query}, visitor, Value, ValueType, @@ -74,6 +71,8 @@ impl<'a> Mssql<'a> { TypeFamily::Boolean => self.write("BIT"), TypeFamily::Uuid => self.write("UNIQUEIDENTIFIER"), TypeFamily::DateTime => self.write("DATETIMEOFFSET"), + TypeFamily::Geometry(_) => self.write("GEOMETRY"), + TypeFamily::Geography(_) => self.write("GEOGRAPHY"), TypeFamily::Bytes(len) => { self.write("VARBINARY(")?; match len { @@ -176,6 +175,12 @@ impl<'a> Mssql<'a> { Ok(()) } + + fn visit_geometry_equals(&mut self, left: Expression<'a>, right: Expression<'a>, not: bool) -> visitor::Result { + self.surround_with("(", ")", |s| s.visit_expression(left))?; + self.surround_with(".STEquals(", ")", |s| s.visit_expression(right))?; + self.write(if not { " = 0" } else { " = 1" }) + } } impl<'a> Visitor<'a> for Mssql<'a> { @@ -203,10 +208,6 @@ impl<'a> Visitor<'a> for Mssql<'a> { Ok(()) } - fn add_parameter(&mut self, value: Value<'a>) { - self.parameters.push(value) - } - /// A point to modify an incoming query to make it compatible with the /// SQL Server. fn compatibility_modifications(&self, query: Query<'a>) -> Query<'a> { @@ -235,6 +236,7 @@ impl<'a> Visitor<'a> for Mssql<'a> { (left_kind, right_kind) => { let (l_alias, r_alias) = (left.alias, right.alias); let (left_xml, right_xml) = (left_kind.is_xml_value(), right_kind.is_xml_value()); + let (left_geom, right_geom) = (left_kind.is_geometry_expr(), right_kind.is_geometry_expr()); let mut left = Expression::from(left_kind); @@ -248,6 +250,12 @@ impl<'a> Visitor<'a> for Mssql<'a> { right = right.alias(alias); } + if left_geom { + return self.visit_geometry_equals(left, right, false); + } else if right_geom { + return self.visit_geometry_equals(right, left, false); + } + if right_xml { self.surround_with("CAST(", " AS NVARCHAR(MAX))", |x| x.visit_expression(left))?; } else { @@ -276,6 +284,7 @@ impl<'a> Visitor<'a> for Mssql<'a> { (left_kind, right_kind) => { let (l_alias, r_alias) = (left.alias, right.alias); let (left_xml, right_xml) = (left_kind.is_xml_value(), right_kind.is_xml_value()); + let (left_geom, right_geom) = (left_kind.is_geometry_expr(), right_kind.is_geometry_expr()); let mut left = Expression::from(left_kind); @@ -289,6 +298,12 @@ impl<'a> Visitor<'a> for Mssql<'a> { right = right.alias(alias); } + if left_geom { + return self.visit_geometry_equals(left, right, true); + } else if right_geom { + return self.visit_geometry_equals(right, left, true); + } + if right_xml { self.surround_with("CAST(", " AS NVARCHAR(MAX))", |x| x.visit_expression(left))?; } else { @@ -361,6 +376,13 @@ impl<'a> Visitor<'a> for Mssql<'a> { // Style 3 is keep all whitespace + internal DTD processing: // https://docs.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql?redirectedfrom=MSDN&view=sql-server-ver15#xml-styles ValueType::Xml(cow) => cow.map(|cow| self.write(format!("CONVERT(XML, N'{cow}', 3)"))), + // TODO@geometry: find a way to avoid cloning + ValueType::Geometry(g) => g + .as_ref() + .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.raw(), false))), + ValueType::Geography(g) => g + .as_ref() + .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.raw(), true))), }; match res { @@ -526,6 +548,10 @@ impl<'a> Visitor<'a> for Mssql<'a> { unimplemented!("Upsert not supported for the underlying database.") } + fn add_parameter(&mut self, value: Value<'a>) { + self.parameters.push(value) + } + fn parameter_substitution(&mut self) -> visitor::Result { self.write("@P")?; self.write(self.parameters.len()) @@ -631,6 +657,50 @@ impl<'a> Visitor<'a> for Mssql<'a> { Ok(()) } + fn visit_geometry_type_equals( + &mut self, + left: Expression<'a>, + geom_type: GeometryType<'a>, + not: bool, + ) -> visitor::Result { + self.surround_with("(", ").STGeometryType()", |s| s.visit_expression(left))?; + + if not { + self.write(" != ")?; + } else { + self.write(" = ")?; + } + + match geom_type { + GeometryType::ColumnRef(column) => { + self.surround_with("(", ").STGeometryType()", |s| s.visit_column(*column)) + } + _ => self.visit_expression(Value::text(geom_type.to_string()).into()), + } + } + + fn visit_geometry_empty(&mut self, left: Expression<'a>, not: bool) -> visitor::Result { + self.surround_with("(", ").STIsEmpty()", |s| s.visit_expression(left))?; + self.write(if not { " = 0" } else { " = 1" }) + } + + fn visit_geometry_valid(&mut self, left: Expression<'a>, not: bool) -> visitor::Result { + self.surround_with("(", ").STIsValid()", |s| s.visit_expression(left))?; + self.write(if not { " = 0" } else { " = 1" }) + } + + fn visit_geometry_within(&mut self, left: Expression<'a>, right: Expression<'a>, not: bool) -> visitor::Result { + self.surround_with("(", ")", |s| s.visit_expression(left))?; + self.surround_with(".STWithin(", ")", |s| s.visit_expression(right))?; + self.write(if not { " = 0" } else { " = 1" }) + } + + fn visit_geometry_intersects(&mut self, left: Expression<'a>, right: Expression<'a>, not: bool) -> visitor::Result { + self.surround_with("(", ")", |s| s.visit_expression(left))?; + self.surround_with(".STIntersects(", ")", |s| s.visit_expression(right))?; + self.write(if not { " = 0" } else { " = 1" }) + } + #[cfg(any(feature = "postgresql", feature = "mysql"))] fn visit_json_extract(&mut self, _json_extract: JsonExtract<'a>) -> visitor::Result { unimplemented!("JSON filtering is not yet supported on MSSQL") @@ -694,6 +764,35 @@ impl<'a> Visitor<'a> for Mssql<'a> { ) -> visitor::Result { unimplemented!("JSON filtering is not yet supported on MSSQL") } + + fn visit_geom_as_text(&mut self, geom: GeomAsText<'a>) -> visitor::Result { + self.write("CASE WHEN ")?; + self.visit_expression(*geom.expression.clone())?; + self.write("IS NULL THEN NULL ELSE ")?; + self.surround_with("CONCAT(", ")", |ref mut s| { + s.write("'SRID=',")?; + s.surround_with("(", ").STSrid", |ref mut s| { + s.visit_expression(*geom.expression.clone()) + })?; + s.write(",';',")?; + s.surround_with("CAST(", " AS VARCHAR(MAX))", |ref mut s| { + s.visit_expression(*geom.expression) + })?; + Ok(()) + })?; + self.write("END")?; + Ok(()) + } + + fn visit_geom_from_text(&mut self, geom: GeomFromText<'a>) -> visitor::Result { + self.write(if geom.geography { "geography" } else { "geometry" })?; + self.surround_with("::STGeomFromText(", ")", |ref mut s| { + s.visit_expression(*geom.wkt_expression)?; + s.write(",")?; + s.visit_expression(*geom.srid_expression)?; + Ok(()) + }) + } } #[cfg(test)] @@ -704,6 +803,7 @@ mod tests { visitor::{Mssql, Visitor}, }; use indoc::indoc; + use std::str::FromStr; fn expected_values<'a, T>(sql: &'static str, params: Vec) -> (String, Vec>) where @@ -1272,6 +1372,22 @@ mod tests { assert!(params.is_empty()); } + #[test] + fn test_raw_geometry() { + let geom = GeometryValue::from_str("SRID=4326;POINT(0 0)").unwrap(); + let (sql, params) = Mssql::build(Select::default().value(Value::geometry(geom).raw())).unwrap(); + assert_eq!("SELECT geometry::STGeomFromText('POINT(0 0)',4326)", sql); + assert!(params.is_empty()); + } + + #[test] + fn test_raw_geography() { + let geom = GeometryValue::from_str("SRID=4326;POINT(0 0)").unwrap(); + let (sql, params) = Mssql::build(Select::default().value(Value::geography(geom).raw())).unwrap(); + assert_eq!("SELECT geography::STGeomFromText('POINT(0 0)',4326)", sql); + assert!(params.is_empty()); + } + #[test] fn test_single_insert() { let insert = Insert::single_into("foo").value("bar", "lol").value("wtf", "meow"); diff --git a/quaint/src/visitor/mysql.rs b/quaint/src/visitor/mysql.rs index 26d0f0d5fd65..2ab3f08abf0e 100644 --- a/quaint/src/visitor/mysql.rs +++ b/quaint/src/visitor/mysql.rs @@ -163,6 +163,13 @@ impl<'a> Visitor<'a> for Mysql<'a> { ValueType::Date(date) => date.map(|date| self.write(format!("'{date}'"))), ValueType::Time(time) => time.map(|time| self.write(format!("'{time}'"))), ValueType::Xml(cow) => cow.as_ref().map(|cow| self.write(format!("'{cow}'"))), + // TODO@geometry: find a way to avoid cloning + ValueType::Geometry(g) => g + .as_ref() + .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.raw(), false))), + ValueType::Geography(g) => g + .as_ref() + .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.raw(), true))), }; match res { @@ -462,6 +469,32 @@ impl<'a> Visitor<'a> for Mysql<'a> { self.write(")") } + fn visit_geometry_type_equals( + &mut self, + left: Expression<'a>, + geom_type: GeometryType<'a>, + not: bool, + ) -> visitor::Result { + self.write("ST_GeometryType")?; + self.surround_with("(", ")", |s| s.visit_expression(left.clone()))?; + + if not { + self.write(" != ")?; + } else { + self.write(" = ")?; + } + + match geom_type { + GeometryType::ColumnRef(column) => { + self.write("ST_GeometryType")?; + self.surround_with("(", ")", |s| s.visit_column(*column)) + } + _ => self.visit_expression(Value::text(geom_type.to_string().to_uppercase()).into()), + }?; + + Ok(()) + } + fn visit_greater_than(&mut self, left: Expression<'a>, right: Expression<'a>) -> visitor::Result { self.visit_numeric_comparison(left, right, ">")?; @@ -607,6 +640,27 @@ impl<'a> Visitor<'a> for Mysql<'a> { Ok(()) } + + fn visit_geom_as_text(&mut self, geom: GeomAsText<'a>) -> visitor::Result { + self.surround_with("CONCAT(", ")", |ref mut s| { + s.write("'SRID=',")?; + s.surround_with("ST_SRID(", ")", |ref mut s| { + s.visit_expression(*geom.expression.clone()) + })?; + s.write(",';',")?; + s.surround_with("ST_AsText(", ")", |ref mut s| s.visit_expression(*geom.expression))?; + Ok(()) + }) + } + + fn visit_geom_from_text(&mut self, geom: GeomFromText<'a>) -> visitor::Result { + self.surround_with("ST_GeomFromText(", ")", |ref mut s| { + s.visit_expression(*geom.wkt_expression)?; + s.write(",")?; + s.visit_expression(*geom.srid_expression)?; + Ok(()) + }) + } } fn get_target_table(query: Query<'_>) -> Option> { @@ -620,6 +674,7 @@ fn get_target_table(query: Query<'_>) -> Option> { #[cfg(test)] mod tests { use crate::visitor::*; + use std::str::FromStr; fn expected_values<'a, T>(sql: &'static str, params: Vec) -> (String, Vec>) where @@ -802,6 +857,26 @@ mod tests { assert!(params.is_empty()); } + #[test] + fn test_raw_geometry() { + let (sql, params) = Mysql::build( + Select::default().value(Value::geometry(GeometryValue::from_str("SRID=4326;POINT(0 0)").unwrap()).raw()), + ) + .unwrap(); + assert_eq!("SELECT ST_GeomFromText('POINT(0 0)',4326)", sql); + assert!(params.is_empty()); + } + + #[test] + fn test_raw_geography() { + let (sql, params) = Mysql::build( + Select::default().value(Value::geography(GeometryValue::from_str("SRID=4326;POINT(0 0)").unwrap()).raw()), + ) + .unwrap(); + assert_eq!("SELECT ST_GeomFromText('POINT(0 0)',4326)", sql); + assert!(params.is_empty()); + } + #[test] fn test_distinct() { let expected_sql = "SELECT DISTINCT `bar` FROM `test`"; diff --git a/quaint/src/visitor/postgres.rs b/quaint/src/visitor/postgres.rs index 648b3f0dc1ec..edc996103c5a 100644 --- a/quaint/src/visitor/postgres.rs +++ b/quaint/src/visitor/postgres.rs @@ -228,6 +228,13 @@ impl<'a> Visitor<'a> for Postgres<'a> { ValueType::DateTime(dt) => dt.map(|dt| self.write(format!("'{}'", dt.to_rfc3339(),))), ValueType::Date(date) => date.map(|date| self.write(format!("'{date}'"))), ValueType::Time(time) => time.map(|time| self.write(format!("'{time}'"))), + // TODO@geometry: find a way to avoid cloning + ValueType::Geometry(g) => g + .as_ref() + .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.raw(), false))), + ValueType::Geography(g) => g + .as_ref() + .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.raw(), true))), }; match res { @@ -499,6 +506,30 @@ impl<'a> Visitor<'a> for Postgres<'a> { } } + fn visit_geometry_type_equals( + &mut self, + left: Expression<'a>, + geom_type: GeometryType<'a>, + not: bool, + ) -> visitor::Result { + self.write("ST_GeometryType")?; + self.surround_with("(", ")", |s| s.visit_expression(left))?; + + if not { + self.write(" != ")?; + } else { + self.write(" = ")?; + } + + match geom_type { + GeometryType::ColumnRef(column) => { + self.write("ST_GeometryType")?; + self.surround_with("(", ")", |s| s.visit_column(*column)) + } + _ => self.visit_expression(Value::text(format!("ST_{geom_type}")).into()), + } + } + fn visit_text_search(&mut self, text_search: crate::prelude::TextSearch<'a>) -> visitor::Result { let len = text_search.exprs.len(); self.surround_with("to_tsvector(concat_ws(' ', ", "))", |s| { @@ -655,11 +686,25 @@ impl<'a> Visitor<'a> for Postgres<'a> { Ok(()) } + + fn visit_geom_as_text(&mut self, geom: GeomAsText<'a>) -> visitor::Result { + self.surround_with("ST_AsEWKT(", ")", |s| s.visit_expression(*geom.expression)) + } + + fn visit_geom_from_text(&mut self, geom: GeomFromText<'a>) -> visitor::Result { + self.surround_with("ST_GeomFromText(", ")", |ref mut s| { + s.visit_expression(*geom.wkt_expression)?; + s.write(",")?; + s.visit_expression(*geom.srid_expression)?; + Ok(()) + }) + } } #[cfg(test)] mod tests { use crate::visitor::*; + use std::str::FromStr; fn expected_values<'a, T>(sql: &'static str, params: Vec) -> (String, Vec>) where @@ -1059,6 +1104,22 @@ mod tests { assert!(params.is_empty()); } + #[test] + fn test_raw_geometry() { + let geom = GeometryValue::from_str("SRID=4326;POINT(0 0)").unwrap(); + let (sql, params) = Postgres::build(Select::default().value(Value::geometry(geom).raw())).unwrap(); + assert_eq!("SELECT ST_GeomFromText('POINT(0 0)',4326)", sql); + assert!(params.is_empty()); + } + + #[test] + fn test_raw_geography() { + let geom = GeometryValue::from_str("SRID=4326;POINT(0 0)").unwrap(); + let (sql, params) = Postgres::build(Select::default().value(Value::geography(geom).raw())).unwrap(); + assert_eq!("SELECT ST_GeomFromText('POINT(0 0)',4326)", sql); + assert!(params.is_empty()); + } + #[test] fn test_raw_comparator() { let (sql, _) = Postgres::build(Select::from_table("foo").so_that("bar".compare_raw("ILIKE", "baz%"))).unwrap(); diff --git a/quaint/src/visitor/sqlite.rs b/quaint/src/visitor/sqlite.rs index 9c15ef651694..2dfe6b709f8f 100644 --- a/quaint/src/visitor/sqlite.rs +++ b/quaint/src/visitor/sqlite.rs @@ -117,6 +117,13 @@ impl<'a> Visitor<'a> for Sqlite<'a> { ValueType::Date(date) => date.map(|date| self.write(format!("'{date}'"))), ValueType::Time(time) => time.map(|time| self.write(format!("'{time}'"))), ValueType::Xml(cow) => cow.as_ref().map(|cow| self.write(format!("'{cow}'"))), + // TODO@geometry: find a way to avoid cloning + ValueType::Geometry(g) => g + .as_ref() + .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.raw(), false))), + ValueType::Geography(g) => g + .as_ref() + .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.raw(), true))), }; match res { @@ -223,14 +230,14 @@ impl<'a> Visitor<'a> for Sqlite<'a> { Ok(()) } - fn parameter_substitution(&mut self) -> visitor::Result { - self.write("?") - } - fn add_parameter(&mut self, value: Value<'a>) { self.parameters.push(value); } + fn parameter_substitution(&mut self) -> visitor::Result { + self.write("?") + } + fn visit_limit_and_offset(&mut self, limit: Option>, offset: Option>) -> visitor::Result { match (limit, offset) { (Some(limit), Some(offset)) => { @@ -274,6 +281,30 @@ impl<'a> Visitor<'a> for Sqlite<'a> { }) } + fn visit_geometry_type_equals( + &mut self, + left: Expression<'a>, + geom_type: GeometryType<'a>, + not: bool, + ) -> visitor::Result { + self.write("ST_GeometryType")?; + self.surround_with("(", ")", |s| s.visit_expression(left.clone()))?; + + if not { + self.write(" != ")?; + } else { + self.write(" = ")?; + } + + match geom_type { + GeometryType::ColumnRef(column) => { + self.write("ST_GeometryType")?; + self.surround_with("(", ")", |s| s.visit_column(*column)) + } + _ => self.visit_expression(Value::text(geom_type.to_string().to_uppercase()).into()), + } + } + #[cfg(any(feature = "postgresql", feature = "mysql"))] fn visit_json_extract(&mut self, _json_extract: JsonExtract<'a>) -> visitor::Result { unimplemented!("JSON filtering is not yet supported on SQLite") @@ -382,11 +413,25 @@ impl<'a> Visitor<'a> for Sqlite<'a> { Ok(()) } + + fn visit_geom_as_text(&mut self, geom: GeomAsText<'a>) -> visitor::Result { + self.surround_with("AsEWKT(", ")", |s| s.visit_expression(*geom.expression)) + } + + fn visit_geom_from_text(&mut self, geom: GeomFromText<'a>) -> visitor::Result { + self.surround_with("ST_GeomFromText(", ")", |ref mut s| { + s.visit_expression(*geom.wkt_expression)?; + s.write(",")?; + s.visit_expression(*geom.srid_expression)?; + Ok(()) + }) + } } #[cfg(test)] mod tests { use crate::{val, visitor::*}; + use std::str::FromStr; fn expected_values<'a, T>(sql: &'static str, params: Vec) -> (String, Vec>) where @@ -937,6 +982,22 @@ mod tests { assert!(params.is_empty()); } + #[test] + fn test_raw_geometry() { + let geom = GeometryValue::from_str("SRID=4326;POINT(0 0)").unwrap(); + let (sql, params) = Postgres::build(Select::default().value(Value::geometry(geom).raw())).unwrap(); + assert_eq!("SELECT ST_GeomFromText('POINT(0 0)',4326)", sql); + assert!(params.is_empty()); + } + + #[test] + fn test_raw_geography() { + let geom = GeometryValue::from_str("SRID=4326;POINT(0 0)").unwrap(); + let (sql, params) = Postgres::build(Select::default().value(Value::geography(geom).raw())).unwrap(); + assert_eq!("SELECT ST_GeomFromText('POINT(0 0)',4326)", sql); + assert!(params.is_empty()); + } + #[test] fn test_default_insert() { let insert = Insert::single_into("foo") diff --git a/query-engine/connector-test-kit-rs/qe-setup/src/lib.rs b/query-engine/connector-test-kit-rs/qe-setup/src/lib.rs index 9756c2efec66..7b588e0dd28e 100644 --- a/query-engine/connector-test-kit-rs/qe-setup/src/lib.rs +++ b/query-engine/connector-test-kit-rs/qe-setup/src/lib.rs @@ -7,10 +7,11 @@ mod mongodb; mod mssql; mod mysql; mod postgres; +mod sqlite; pub use schema_core::schema_connector::ConnectorError; -use self::{cockroachdb::*, mongodb::*, mssql::*, mysql::*, postgres::*}; +use self::{cockroachdb::*, mongodb::*, mssql::*, mysql::*, postgres::*, sqlite::*}; use enumflags2::BitFlags; use psl::{builtin_connectors::*, Datasource}; use schema_core::schema_connector::{ConnectorResult, DiffTarget, SchemaConnector}; @@ -50,12 +51,7 @@ pub async fn setup(prisma_schema: &str, db_schemas: &[&str]) -> ConnectorResult< let mut connector = sql_schema_connector::SqlSchemaConnector::new_mysql(); diff_and_apply(prisma_schema, url, &mut connector).await } - provider if SQLITE.is_provider(provider) => { - std::fs::remove_file(source.url.as_literal().unwrap().trim_start_matches("file:")).ok(); - let mut connector = sql_schema_connector::SqlSchemaConnector::new_sqlite(); - diff_and_apply(prisma_schema, url, &mut connector).await - } - + provider if SQLITE.is_provider(provider) => sqlite_setup(url, source, prisma_schema).await, provider if MONGODB.is_provider(provider) => mongo_setup(prisma_schema, &url).await, x => unimplemented!("Connector {} is not supported yet", x), diff --git a/query-engine/connector-test-kit-rs/qe-setup/src/postgres.rs b/query-engine/connector-test-kit-rs/qe-setup/src/postgres.rs index 6bbba8564cae..2e47a6315982 100644 --- a/query-engine/connector-test-kit-rs/qe-setup/src/postgres.rs +++ b/query-engine/connector-test-kit-rs/qe-setup/src/postgres.rs @@ -38,6 +38,9 @@ pub(crate) async fn postgres_setup(url: String, prisma_schema: &str, db_schemas: .map_err(|e| ConnectorError::from_source(e, ""))?; } + let conn = Quaint::new(parsed_url.as_ref()).await.unwrap(); + conn.raw_cmd("CREATE EXTENSION IF NOT EXISTS postgis").await.ok(); + let mut connector = sql_schema_connector::SqlSchemaConnector::new_postgres(); crate::diff_and_apply(prisma_schema, url, &mut connector).await } diff --git a/query-engine/connector-test-kit-rs/qe-setup/src/sqlite.rs b/query-engine/connector-test-kit-rs/qe-setup/src/sqlite.rs new file mode 100644 index 000000000000..37085b191ca7 --- /dev/null +++ b/query-engine/connector-test-kit-rs/qe-setup/src/sqlite.rs @@ -0,0 +1,11 @@ +use psl::Datasource; +use quaint::{prelude::*, single::Quaint}; +use schema_core::schema_connector::ConnectorResult; + +pub(crate) async fn sqlite_setup(url: String, source: Datasource, prisma_schema: &str) -> ConnectorResult<()> { + std::fs::remove_file(source.url.as_literal().unwrap().trim_start_matches("file:")).ok(); + let mut connector = sql_schema_connector::SqlSchemaConnector::new_sqlite(); + let client = Quaint::new(&url).await.unwrap(); + client.query_raw("SELECT InitSpatialMetaData()", &[]).await.unwrap(); + crate::diff_and_apply(prisma_schema, url, &mut connector).await +} diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/src/schemas/geometry.rs b/query-engine/connector-test-kit-rs/query-engine-tests/src/schemas/geometry.rs new file mode 100644 index 000000000000..c52442912461 --- /dev/null +++ b/query-engine/connector-test-kit-rs/query-engine-tests/src/schemas/geometry.rs @@ -0,0 +1,25 @@ +use indoc::indoc; + +/// Basic Test model containing a single geometry field. +pub fn geometry() -> String { + let schema = indoc! { + "model TestModel { + #id(id, Int, @id) + geometry GeoJson + }" + }; + + schema.to_owned() +} + +/// Basic Test model containing a single optional geometry field. +pub fn geometry_opt() -> String { + let schema = indoc! { + "model TestModel { + #id(id, Int, @id) + geometry GeoJson? + }" + }; + + schema.to_owned() +} diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/src/schemas/mod.rs b/query-engine/connector-test-kit-rs/query-engine-tests/src/schemas/mod.rs index cd9d2d9d1cb2..797235a679cb 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/src/schemas/mod.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/src/schemas/mod.rs @@ -1,11 +1,13 @@ mod basic; mod composites; +mod geometry; mod json; mod many_to_many; mod one_to_many; pub use basic::*; pub use composites::*; +pub use geometry::*; pub use json::*; pub use many_to_many::*; pub use one_to_many::*; diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/new/metrics.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/new/metrics.rs index cd270bb334c6..0c1e3788c5fa 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/new/metrics.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/new/metrics.rs @@ -35,13 +35,13 @@ mod metrics { let total_operations = get_counter(&json, PRISMA_CLIENT_QUERIES_TOTAL); match runner.connector_version() { - Sqlite(_) => assert_eq!(total_queries, 9), + Sqlite(_) => assert_eq!(total_queries, 10), SqlServer(_) => assert_eq!(total_queries, 17), MongoDb(_) => assert_eq!(total_queries, 5), CockroachDb(_) => (), // not deterministic MySql(_) => assert_eq!(total_queries, 12), Vitess(_) => assert_eq!(total_queries, 11), - Postgres(_) => assert_eq!(total_queries, 7), + Postgres(_) => assert_eq!(total_queries, 9), } assert_eq!(total_operations, 2); diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs new file mode 100644 index 000000000000..fe29e6dc95e2 --- /dev/null +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs @@ -0,0 +1,123 @@ +use query_engine_tests::*; + +#[test_suite( + schema(schema), + capabilities(GeoJsonGeometry), + exclude(Postgres(9, 10, 11, 12, 13, 14, 15, "pgbouncer")) +)] +mod geometry_filter_spec { + use query_engine_tests::run_query; + + fn schema() -> String { + let schema = indoc! { + r#" + model TestModel { + #id(id, Int, @id) + geom GeoJson? + } + "# + }; + + schema.to_owned() + } + + #[connector_test] + async fn basic_where(runner: Runner) -> TestResult<()> { + test_data(&runner).await?; + + insta::assert_snapshot!( + run_query!(&runner, r#"query { findManyTestModel(where: { geom: { equals: "{\"type\":\"Point\",\"coordinates\":[0, 0]}" }}) { id }}"#), + @r###"{"data":{"findManyTestModel":[{"id":1}]}}"### + ); + + insta::assert_snapshot!( + run_query!(&runner, r#"query { findManyTestModel(where: { AND: [{ geom: { not: "{\"type\":\"Point\",\"coordinates\":[0, 0]}" }}, { geom: { not: null }}] }) { id }}"#), + @r###"{"data":{"findManyTestModel":[{"id":2}]}}"### + ); + + insta::assert_snapshot!( + run_query!(&runner, r#"query { findManyTestModel(where: { geom: { not: null }}) { id }}"#), + @r###"{"data":{"findManyTestModel":[{"id":1},{"id":2}]}}"### + ); + + Ok(()) + } + + #[connector_test] + async fn where_shorthands(runner: Runner) -> TestResult<()> { + test_data(&runner).await?; + + insta::assert_snapshot!( + run_query!(&runner, r#"query { findManyTestModel(where: { geom: "{\"type\":\"Point\",\"coordinates\":[0, 0]}" }) { id }}"#), + @r###"{"data":{"findManyTestModel":[{"id":1}]}}"### + ); + + match_connector_result!( + &runner, + r#"query { findManyTestModel(where: { geom: null }) { id }}"#, + // MongoDB excludes undefined fields + MongoDb(_) => vec![r#"{"data":{"findManyTestModel":[]}}"#], + _ => vec![r#"{"data":{"findManyTestModel":[{"id":3}]}}"#] + ); + + Ok(()) + } + + #[connector_test(capabilities(GeometryFiltering))] + async fn geometric_comparison_filters(runner: Runner) -> TestResult<()> { + test_data(&runner).await?; + + // geoWithin + insta::assert_snapshot!( + run_query!(&runner, r#"query { findManyTestModel(where: { geom: { geoWithin: "{\"type\":\"Polygon\",\"coordinates\":[[[1,1],[1,4],[4,4],[4,1],[1,1]]]}" }}) { id }}"#), + @r###"{"data":{"findManyTestModel":[{"id":2}]}}"### + ); + + // Not geoWithin + insta::assert_snapshot!( + run_query!(&runner, r#"query { findManyTestModel(where: { geom: { not: { geoWithin: "{\"type\":\"Polygon\",\"coordinates\":[[[1,1],[1,4],[4,4],[4,1],[1,1]]]}" }}}) { id }}"#), + @r###"{"data":{"findManyTestModel":[{"id":1}]}}"### + ); + + // geoIntersects + insta::assert_snapshot!( + run_query!(&runner, r#"query { findManyTestModel(where: { geom: { geoIntersects: "{\"type\":\"Point\",\"coordinates\":[0, 0]}" }}) { id }}"#), + @r###"{"data":{"findManyTestModel":[{"id":1}]}}"### + ); + + // Not geoIntersects + insta::assert_snapshot!( + run_query!(&runner, r#"query { findManyTestModel(where: { geom: { not: { geoIntersects: "{\"type\":\"Point\",\"coordinates\":[0, 0]}" }}}) { id }}"#), + @r###"{"data":{"findManyTestModel":[{"id":2}]}}"### + ); + + Ok(()) + } + + async fn test_data(runner: &Runner) -> TestResult<()> { + runner + .query(indoc! { r#" + mutation { createOneTestModel(data: { + id: 1, + geom: "{\"type\":\"Point\",\"coordinates\":[0, 0]}", + }) { id }}"# }) + .await? + .assert_success(); + + runner + .query(indoc! { r#" + mutation { createOneTestModel(data: { + id: 2, + geom: "{\"type\":\"Polygon\",\"coordinates\":[[[2,2],[2,3],[3,3],[3,2],[2,2]]]}", + }) { id }}"# }) + .await? + .assert_success(); + + runner + .query(indoc! { r#"mutation { createOneTestModel(data: { id: 3 }) { id }}"# }) + .await? + .assert_success(); + + Ok(()) + } +} diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/mod.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/mod.rs index a87b522614ef..fb303ab558f2 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/mod.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/mod.rs @@ -9,6 +9,7 @@ pub mod field_reference; pub mod filter_regression; pub mod filter_unwrap; pub mod filters; +pub mod geometry_filter; pub mod insensitive_filters; pub mod json; pub mod json_filters; diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mod.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mod.rs index fb814cca9977..ed35a5c04604 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mod.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mod.rs @@ -2,3 +2,4 @@ mod mongodb; mod mysql; mod postgres; mod sql_server; +mod sqlite; diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mongodb.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mongodb.rs index 0ee4912574aa..4cbbc4441eca 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mongodb.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mongodb.rs @@ -17,6 +17,7 @@ mod mongodb { bool Boolean @test.Bool bin Bytes @test.BinData bin_oid Bytes @test.ObjectId + geom GeoJson }"# }; @@ -38,6 +39,7 @@ mod mongodb { bool: true bin: "dGVzdA==" bin_oid: "YeUuxAwj5igGOSD0" + geom: "{\"type\": \"Point\", \"coordinates\": [0, 0]}" } ) { int @@ -49,9 +51,10 @@ mod mongodb { bool bin bin_oid + geom } }"#), - @r###"{"data":{"createOneTestModel":{"int":2147483647,"long":32767,"bInt":"9223372036854775807","float":3.1234,"oid":"61e1425609c85b5e01817cc5","str":"test","bool":true,"bin":"dGVzdA==","bin_oid":"YeUuxAwj5igGOSD0"}}}"### + @r###"{"data":{"createOneTestModel":{"int":2147483647,"long":32767,"bInt":"9223372036854775807","float":3.1234,"oid":"61e1425609c85b5e01817cc5","str":"test","bool":true,"bin":"dGVzdA==","bin_oid":"YeUuxAwj5igGOSD0","geom":"{\"type\":\"Point\",\"coordinates\":[0,0]}"}}}"### ); Ok(()) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs index 4d3c3137f4a2..4c1c80ee7da0 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs @@ -430,4 +430,208 @@ mod mysql { Ok(()) } + + fn schema_ewkt_geometry_types() -> String { + let schema = indoc! { + r#"model Model { + #id(id, String, @id, @default(cuid())) + geometry Geometry @test.Geometry + point Geometry @test.Point + line Geometry @test.LineString + poly Geometry @test.Polygon + multipoint Geometry @test.MultiPoint + multiline Geometry @test.MultiLineString + multipoly Geometry @test.MultiPolygon + collection Geometry @test.GeometryCollection + }"# + }; + + schema.to_owned() + } + + // "MySQL native spatial types" should "work" + #[connector_test(schema(schema_ewkt_geometry_types))] + async fn native_ewkt_geometry_types(runner: Runner) -> TestResult<()> { + insta::assert_snapshot!( + run_query!(&runner, r#"mutation { + createOneModel( + data: { + geometry: "POINT(1 2)" + point: "POINT(1 2)" + line: "LINESTRING(1 2,3 4)" + poly: "POLYGON((1 2,3 4,5 6,1 2))" + multipoint: "MULTIPOINT(1 2)" + multiline: "MULTILINESTRING((1 2,3 4))" + multipoly: "MULTIPOLYGON(((1 2,3 4,5 6,1 2)))" + collection: "GEOMETRYCOLLECTION(POINT(1 2))" + } + ) { + geometry, + point + line + poly + multipoint + multiline + multipoly + collection + } + }"#), + @r###"{"data":{"createOneModel":{"geometry":"POINT(1 2)","point":"POINT(1 2)","line":"LINESTRING(1 2,3 4)","poly":"POLYGON((1 2,3 4,5 6,1 2))","multipoint":"MULTIPOINT(1 2)","multiline":"MULTILINESTRING((1 2,3 4))","multipoly":"MULTIPOLYGON(((1 2,3 4,5 6,1 2)))","collection":"GEOMETRYCOLLECTION(POINT(1 2))"}}}"### + ); + + Ok(()) + } + + fn schema_geojson_geometry_types() -> String { + let schema = indoc! { + r#"model Model { + #id(id, String, @id, @default(cuid())) + geometry GeoJson @test.Geometry + point GeoJson @test.Point + line GeoJson @test.LineString + poly GeoJson @test.Polygon + multipoint GeoJson @test.MultiPoint + multiline GeoJson @test.MultiLineString + multipoly GeoJson @test.MultiPolygon + collection GeoJson @test.GeometryCollection + }"# + }; + + schema.to_owned() + } + + // "MySQL native spatial types" should "work" + #[connector_test(schema(schema_geojson_geometry_types))] + async fn native_geojson_geometry_types(runner: Runner) -> TestResult<()> { + insta::assert_snapshot!( + run_query!(&runner, r#"mutation { + createOneModel( + data: { + geometry: "{\"type\":\"Point\",\"coordinates\":[1,2]}" + point: "{\"type\":\"Point\",\"coordinates\":[1,2]}" + line: "{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}" + poly: "{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}" + multipoint: "{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}" + multiline: "{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}" + multipoly: "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}" + collection: "{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}" + } + ) { + geometry, + point + line + poly + multipoint + multiline + multipoly + collection + } + }"#), + @r###"{"data":{"createOneModel":{"geometry":"{\"type\": \"Point\", \"coordinates\": [1,2]}","point":"{\"type\": \"Point\", \"coordinates\": [1,2]}","line":"{\"type\": \"LineString\", \"coordinates\": [[1,2],[3,4]]}","poly":"{\"type\": \"Polygon\", \"coordinates\": [[[1,2],[3,4],[5,6],[1,2]]]}","multipoint":"{\"type\": \"MultiPoint\", \"coordinates\": [[1,2]]}","multiline":"{\"type\": \"MultiLineString\", \"coordinates\": [[[1,2],[3,4]]]}","multipoly":"{\"type\": \"MultiPolygon\", \"coordinates\": [[[[1,2],[3,4],[5,6],[1,2]]]]}","collection":"{\"type\": \"GeometryCollection\", \"geometries\": [{\"type\": \"Point\", \"coordinates\": [1,2]}]}"}}}"### + ); + + Ok(()) + } + + fn schema_geometry_srid_types() -> String { + let schema = indoc! { + r#"model Model { + #id(id, String, @id, @default(cuid())) + geometry Geometry @test.Geometry(4326) + point Geometry @test.Point(4326) + line Geometry @test.LineString(4326) + poly Geometry @test.Polygon(4326) + multipoint Geometry @test.MultiPoint(4326) + multiline Geometry @test.MultiLineString(4326) + multipoly Geometry @test.MultiPolygon(4326) + collection Geometry @test.GeometryCollection(4326) + }"# + }; + + schema.to_owned() + } + + // "MySQL native spatial srid types" should "work" + #[connector_test(only(MySQL(8)), schema(schema_geometry_srid_types))] + async fn native_geometry_srid_types(runner: Runner) -> TestResult<()> { + insta::assert_snapshot!( + run_query!(&runner, r#"mutation { + createOneModel( + data: { + geometry: "SRID=4326;POINT(1 2)" + point: "SRID=4326;POINT(1 2)" + line: "SRID=4326;LINESTRING(1 2,3 4)" + poly: "SRID=4326;POLYGON((1 2,3 4,5 6,1 2))" + multipoint: "SRID=4326;MULTIPOINT(1 2)" + multiline: "SRID=4326;MULTILINESTRING((1 2,3 4))" + multipoly: "SRID=4326;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))" + collection: "SRID=4326;GEOMETRYCOLLECTION(POINT(1 2))" + } + ) { + geometry + point + line + poly + multipoint + multiline + multipoly + collection + } + }"#), + @r###"{"data":{"createOneModel":{"geometry":"SRID=4326;POINT(1 2)","point":"SRID=4326;POINT(1 2)","line":"SRID=4326;LINESTRING(1 2,3 4)","poly":"SRID=4326;POLYGON((1 2,3 4,5 6,1 2))","multipoint":"SRID=4326;MULTIPOINT(1 2)","multiline":"SRID=4326;MULTILINESTRING((1 2,3 4))","multipoly":"SRID=4326;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))","collection":"SRID=4326;GEOMETRYCOLLECTION(POINT(1 2))"}}}"### + ); + + Ok(()) + } + + fn schema_geojson_srid_geometry_types() -> String { + let schema = indoc! { + r#"model Model { + #id(id, String, @id, @default(cuid())) + geometry GeoJson @test.Geometry(4326) + point GeoJson @test.Point(4326) + line GeoJson @test.LineString(4326) + poly GeoJson @test.Polygon(4326) + multipoint GeoJson @test.MultiPoint(4326) + multiline GeoJson @test.MultiLineString(4326) + multipoly GeoJson @test.MultiPolygon(4326) + collection GeoJson @test.GeometryCollection(4326) + }"# + }; + + schema.to_owned() + } + + // "MySQL native spatial types" should "work" + #[connector_test(schema(schema_geojson_srid_geometry_types))] + async fn native_geojson_srid_geometry_types(runner: Runner) -> TestResult<()> { + insta::assert_snapshot!( + run_query!(&runner, r#"mutation { + createOneModel( + data: { + geometry: "{\"type\":\"Point\",\"coordinates\":[1,2]}" + point: "{\"type\":\"Point\",\"coordinates\":[1,2]}" + line: "{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}" + poly: "{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}" + multipoint: "{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}" + multiline: "{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}" + multipoly: "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}" + collection: "{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}" + } + ) { + geometry, + point + line + poly + multipoint + multiline + multipoly + collection + } + }"#), + @r###"{"data":{"createOneModel":{"geometry":"{\"type\": \"Point\", \"coordinates\": [1,2]}","point":"{\"type\": \"Point\", \"coordinates\": [1,2]}","line":"{\"type\": \"LineString\", \"coordinates\": [[1,2],[3,4]]}","poly":"{\"type\": \"Polygon\", \"coordinates\": [[[1,2],[3,4],[5,6],[1,2]]]}","multipoint":"{\"type\": \"MultiPoint\", \"coordinates\": [[1,2]]}","multiline":"{\"type\": \"MultiLineString\", \"coordinates\": [[[1,2],[3,4]]]}","multipoly":"{\"type\": \"MultiPolygon\", \"coordinates\": [[[[1,2],[3,4],[5,6],[1,2]]]]}","collection":"{\"type\": \"GeometryCollection\", \"geometries\": [{\"type\": \"Point\", \"coordinates\": [1,2]}]}"}}}"### + ); + + Ok(()) + } } diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/postgres.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/postgres.rs index 2d487ec4f137..8a8312c5ebde 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/postgres.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/postgres.rs @@ -346,4 +346,396 @@ mod postgres { Ok(()) } + + fn schema_ewkt_geometry() -> String { + let schema = indoc! { + r#"model Model { + @@schema("test") + #id(id, String, @id, @default(cuid())) + geometry Geometry @test.Geometry(Geometry) + geometry_point Geometry @test.Geometry(Point) + geometry_line Geometry @test.Geometry(LineString) + geometry_poly Geometry @test.Geometry(Polygon) + geometry_multipoint Geometry @test.Geometry(MultiPoint) + geometry_multiline Geometry @test.Geometry(MultiLineString) + geometry_multipoly Geometry @test.Geometry(MultiPolygon) + geometry_collection Geometry @test.Geometry(GeometryCollection) + }"# + }; + + schema.to_owned() + } + + // "PostGIS common geometry types" should "work" + #[connector_test( + only(Postgres("15-postgis"), CockroachDb), + schema(schema_ewkt_geometry), + db_schemas("public", "test") + )] + async fn native_ewkt_geometry(runner: Runner) -> TestResult<()> { + insta::assert_snapshot!( + run_query!(&runner, r#"mutation { + createOneModel( + data: { + geometry: "POINT(1 2)" + geometry_point: "POINT(1 2)" + geometry_line: "LINESTRING(1 2,3 4)" + geometry_poly: "POLYGON((1 2,3 4,5 6,1 2))" + geometry_multipoint: "MULTIPOINT(1 2)" + geometry_multiline: "MULTILINESTRING((1 2,3 4))" + geometry_multipoly: "MULTIPOLYGON(((1 2,3 4,5 6,1 2)))" + geometry_collection: "GEOMETRYCOLLECTION(POINT(1 2))" + } + ) { + geometry + geometry_point + geometry_line + geometry_poly + geometry_multipoint + geometry_multiline + geometry_multipoly + geometry_collection + } + }"#), + @r###"{"data":{"createOneModel":{"geometry":"POINT(1 2)","geometry_point":"POINT(1 2)","geometry_line":"LINESTRING(1 2,3 4)","geometry_poly":"POLYGON((1 2,3 4,5 6,1 2))","geometry_multipoint":"MULTIPOINT(1 2)","geometry_multiline":"MULTILINESTRING((1 2,3 4))","geometry_multipoly":"MULTIPOLYGON(((1 2,3 4,5 6,1 2)))","geometry_collection":"GEOMETRYCOLLECTION(POINT(1 2))"}}}"### + ); + + Ok(()) + } + + fn schema_ewkt_geometry_srid() -> String { + let schema = indoc! { + r#"model Model { + @@schema("test") + #id(id, String, @id, @default(cuid())) + geometry Geometry @test.Geometry(Geometry, 3857) + geometry_point Geometry @test.Geometry(Point, 3857) + geometry_line Geometry @test.Geometry(LineString, 3857) + geometry_poly Geometry @test.Geometry(Polygon, 3857) + geometry_multipoint Geometry @test.Geometry(MultiPoint, 3857) + geometry_multiline Geometry @test.Geometry(MultiLineString, 3857) + geometry_multipoly Geometry @test.Geometry(MultiPolygon, 3857) + geometry_collection Geometry @test.Geometry(GeometryCollection, 3857) + }"# + }; + + schema.to_owned() + } + + // "PostGIS common geometry types with srid" should "work" + #[connector_test( + only(Postgres("15-postgis"), CockroachDb), + schema(schema_ewkt_geometry_srid), + db_schemas("public", "test") + )] + async fn native_geometry_srid(runner: Runner) -> TestResult<()> { + insta::assert_snapshot!( + run_query!(&runner, r#"mutation { + createOneModel( + data: { + geometry: "SRID=3857;POINT(1 2)" + geometry_point: "SRID=3857;POINT(1 2)" + geometry_line: "SRID=3857;LINESTRING(1 2,3 4)" + geometry_poly: "SRID=3857;POLYGON((1 2,3 4,5 6,1 2))" + geometry_multipoint: "SRID=3857;MULTIPOINT(1 2)" + geometry_multiline: "SRID=3857;MULTILINESTRING((1 2,3 4))" + geometry_multipoly: "SRID=3857;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))" + geometry_collection: "SRID=3857;GEOMETRYCOLLECTION(POINT(1 2))" + } + ) { + geometry + geometry_point + geometry_line + geometry_poly + geometry_multipoint + geometry_multiline + geometry_multipoly + geometry_collection + } + }"#), + @r###"{"data":{"createOneModel":{"geometry":"SRID=3857;POINT(1 2)","geometry_point":"SRID=3857;POINT(1 2)","geometry_line":"SRID=3857;LINESTRING(1 2,3 4)","geometry_poly":"SRID=3857;POLYGON((1 2,3 4,5 6,1 2))","geometry_multipoint":"SRID=3857;MULTIPOINT(1 2)","geometry_multiline":"SRID=3857;MULTILINESTRING((1 2,3 4))","geometry_multipoly":"SRID=3857;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))","geometry_collection":"SRID=3857;GEOMETRYCOLLECTION(POINT(1 2))"}}}"### + ); + + Ok(()) + } + + fn schema_ewkt_geography() -> String { + let schema = indoc! { + r#"model Model { + @@schema("test") + #id(id, String, @id, @default(cuid())) + geography Geometry @test.Geography(Geometry) + geography_point Geometry @test.Geography(Point) + geography_line Geometry @test.Geography(LineString) + geography_poly Geometry @test.Geography(Polygon) + geography_multipoint Geometry @test.Geography(MultiPoint) + geography_multiline Geometry @test.Geography(MultiLineString) + geography_multipoly Geometry @test.Geography(MultiPolygon) + geography_collection Geometry @test.Geography(GeometryCollection) + }"# + }; + + schema.to_owned() + } + + // "PostGIS common geography types" should "work" + #[connector_test( + only(Postgres("15-postgis"), CockroachDb), + schema(schema_ewkt_geography), + db_schemas("public", "test") + )] + async fn native_ewkt_geography(runner: Runner) -> TestResult<()> { + insta::assert_snapshot!( + run_query!(&runner, r#"mutation { + createOneModel( + data: { + geography: "SRID=4326;POINT(1 2)" + geography_point: "SRID=4326;POINT(1 2)" + geography_line: "SRID=4326;LINESTRING(1 2,3 4)" + geography_poly: "SRID=4326;POLYGON((1 2,3 4,5 6,1 2))" + geography_multipoint: "SRID=4326;MULTIPOINT(1 2)" + geography_multiline: "SRID=4326;MULTILINESTRING((1 2,3 4))" + geography_multipoly: "SRID=4326;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))" + geography_collection: "SRID=4326;GEOMETRYCOLLECTION(POINT(1 2))" + } + ) { + geography + geography_point + geography_line + geography_poly + geography_multipoint + geography_multiline + geography_multipoly + geography_collection + } + }"#), + @r###"{"data":{"createOneModel":{"geography":"SRID=4326;POINT(1 2)","geography_point":"SRID=4326;POINT(1 2)","geography_line":"SRID=4326;LINESTRING(1 2,3 4)","geography_poly":"SRID=4326;POLYGON((1 2,3 4,5 6,1 2))","geography_multipoint":"SRID=4326;MULTIPOINT(1 2)","geography_multiline":"SRID=4326;MULTILINESTRING((1 2,3 4))","geography_multipoly":"SRID=4326;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))","geography_collection":"SRID=4326;GEOMETRYCOLLECTION(POINT(1 2))"}}}"### + ); + + Ok(()) + } + + fn schema_ewkt_geography_srid() -> String { + let schema = indoc! { + r#"model Model { + @@schema("test") + #id(id, String, @id, @default(cuid())) + geography Geometry @test.Geography(Geometry, 9000) + geography_point Geometry @test.Geography(Point, 9000) + geography_line Geometry @test.Geography(LineString, 9000) + geography_poly Geometry @test.Geography(Polygon, 9000) + geography_multipoint Geometry @test.Geography(MultiPoint, 9000) + geography_multiline Geometry @test.Geography(MultiLineString, 9000) + geography_multipoly Geometry @test.Geography(MultiPolygon, 9000) + geography_collection Geometry @test.Geography(GeometryCollection, 9000) + }"# + }; + + schema.to_owned() + } + + // "PostGIS common geography types with srid" should "work" + #[connector_test( + only(Postgres("15-postgis"), CockroachDb), + schema(schema_ewkt_geography_srid), + db_schemas("public", "test") + )] + async fn native_ewkt_geography_srid(runner: Runner) -> TestResult<()> { + insta::assert_snapshot!( + run_query!(&runner, r#"mutation { + createOneModel( + data: { + geography: "SRID=9000;POINT(1 2)" + geography_point: "SRID=9000;POINT(1 2)" + geography_line: "SRID=9000;LINESTRING(1 2,3 4)" + geography_poly: "SRID=9000;POLYGON((1 2,3 4,5 6,1 2))" + geography_multipoint: "SRID=9000;MULTIPOINT(1 2)" + geography_multiline: "SRID=9000;MULTILINESTRING((1 2,3 4))" + geography_multipoly: "SRID=9000;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))" + geography_collection: "SRID=9000;GEOMETRYCOLLECTION(POINT(1 2))" + } + ) { + geography + geography_point + geography_line + geography_poly + geography_multipoint + geography_multiline + geography_multipoly + geography_collection + } + }"#), + @r###"{"data":{"createOneModel":{"geography":"SRID=9000;POINT(1 2)","geography_point":"SRID=9000;POINT(1 2)","geography_line":"SRID=9000;LINESTRING(1 2,3 4)","geography_poly":"SRID=9000;POLYGON((1 2,3 4,5 6,1 2))","geography_multipoint":"SRID=9000;MULTIPOINT(1 2)","geography_multiline":"SRID=9000;MULTILINESTRING((1 2,3 4))","geography_multipoly":"SRID=9000;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))","geography_collection":"SRID=9000;GEOMETRYCOLLECTION(POINT(1 2))"}}}"### + ); + + Ok(()) + } + + fn schema_extra_geometry() -> String { + let schema = indoc! { + r#"model Model { + @@schema("test") + #id(id, String, @id, @default(cuid())) + geometry_triangle Geometry @test.Geometry(Triangle) + geometry_circularstring Geometry @test.Geometry(CircularString) + geometry_compoundcurve Geometry @test.Geometry(CompoundCurve) + geometry_curvepolygon Geometry @test.Geometry(CurvePolygon) + geometry_multicurve Geometry @test.Geometry(MultiCurve) + geometry_multisurface Geometry @test.Geometry(MultiSurface) + geometry_polyhedral Geometry @test.Geometry(PolyhedralSurfaceZ) + geometry_tin Geometry @test.Geometry(Tin) + }"# + }; + + schema.to_owned() + } + + // "PostGIS extra geometry types" should "work" + #[connector_test( + only(Postgres("15-postgis")), + schema(schema_extra_geometry), + db_schemas("public", "test") + )] + async fn native_extra_geometry(runner: Runner) -> TestResult<()> { + insta::assert_snapshot!( + run_query!(&runner, r#"mutation { + createOneModel( + data: { + geometry_triangle: "TRIANGLE((0 0,1 1,2 0,0 0))" + geometry_circularstring: "CIRCULARSTRING(0 0,4 0,4 4,0 4,0 0)" + geometry_compoundcurve: "COMPOUNDCURVE(CIRCULARSTRING(0 0,1 1,1 0),(1 0,0 1))" + geometry_curvepolygon: "CURVEPOLYGON(CIRCULARSTRING(0 0,4 0,4 4,0 4,0 0),(1 1,3 3,3 1,1 1))" + geometry_multicurve: "MULTICURVE((0 0,5 5),CIRCULARSTRING(4 0,4 4,8 4))" + geometry_multisurface: "MULTISURFACE(CURVEPOLYGON(CIRCULARSTRING(0 0,4 0,4 4,0 4,0 0),(1 1,3 3,3 1,1 1)),((10 10,14 12,11 10,10 10),(11 11,11.5 11,11 11.5,11 11)))" + geometry_polyhedral:"POLYHEDRALSURFACE(((0 0 0,1 0 0,0 1 0,0 0 1,0 0 0)))" + geometry_tin: "TIN(((80 130,50 160,80 70,80 130)),((50 160,10 190,10 70,50 160)),((80 70,50 160,10 70,80 70)),((120 160,120 190,50 160,120 160)),((120 190,10 190,50 160,120 190)))" + } + ) { + geometry_triangle + geometry_circularstring + geometry_compoundcurve + geometry_curvepolygon + geometry_multicurve + geometry_multisurface + geometry_polyhedral + geometry_tin + } + }"#), + @r###"{"data":{"createOneModel":{"geometry_triangle":"TRIANGLE((0 0,1 1,2 0,0 0))","geometry_circularstring":"CIRCULARSTRING(0 0,4 0,4 4,0 4,0 0)","geometry_compoundcurve":"COMPOUNDCURVE(CIRCULARSTRING(0 0,1 1,1 0),(1 0,0 1))","geometry_curvepolygon":"CURVEPOLYGON(CIRCULARSTRING(0 0,4 0,4 4,0 4,0 0),(1 1,3 3,3 1,1 1))","geometry_multicurve":"MULTICURVE((0 0,5 5),CIRCULARSTRING(4 0,4 4,8 4))","geometry_multisurface":"MULTISURFACE(CURVEPOLYGON(CIRCULARSTRING(0 0,4 0,4 4,0 4,0 0),(1 1,3 3,3 1,1 1)),((10 10,14 12,11 10,10 10),(11 11,11.5 11,11 11.5,11 11)))","geometry_polyhedral":"POLYHEDRALSURFACE(((0 0 0,1 0 0,0 1 0,0 0 1,0 0 0)))","geometry_tin":"TIN(((80 130,50 160,80 70,80 130)),((50 160,10 190,10 70,50 160)),((80 70,50 160,10 70,80 70)),((120 160,120 190,50 160,120 160)),((120 190,10 190,50 160,120 190)))"}}}"### + ); + + Ok(()) + } + + fn schema_geojson_geometry() -> String { + let schema = indoc! { + r#"model Model { + @@schema("test") + #id(id, String, @id, @default(cuid())) + geometry GeoJson @test.Geometry(Geometry, 4326) + geometry_point GeoJson @test.Geometry(Point, 4326) + geometry_line GeoJson @test.Geometry(LineString, 4326) + geometry_poly GeoJson @test.Geometry(Polygon, 4326) + geometry_multipoint GeoJson @test.Geometry(MultiPoint, 4326) + geometry_multiline GeoJson @test.Geometry(MultiLineString, 4326) + geometry_multipoly GeoJson @test.Geometry(MultiPolygon, 4326) + geometry_collection GeoJson @test.Geometry(GeometryCollection, 4326) + }"# + }; + + schema.to_owned() + } + + // "PostGIS common geometry types" should "work" with GeoJSON + #[connector_test( + only(Postgres("15-postgis"), CockroachDb), + schema(schema_geojson_geometry), + db_schemas("public", "test") + )] + async fn native_geojson_geometry(runner: Runner) -> TestResult<()> { + insta::assert_snapshot!( + run_query!(&runner, r#"mutation { + createOneModel( + data: { + geometry: "{\"type\":\"Point\",\"coordinates\":[1,2]}" + geometry_point: "{\"type\":\"Point\",\"coordinates\":[1,2]}" + geometry_line: "{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}" + geometry_poly: "{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}" + geometry_multipoint: "{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}" + geometry_multiline: "{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}" + geometry_multipoly: "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}" + geometry_collection: "{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}" + } + ) { + geometry + geometry_point + geometry_line + geometry_poly + geometry_multipoint + geometry_multiline + geometry_multipoly + geometry_collection + } + }"#), + @r###"{"data":{"createOneModel":{"geometry":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geometry_point":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geometry_line":"{\"type\": \"LineString\", \"coordinates\": [[1,2],[3,4]]}","geometry_poly":"{\"type\": \"Polygon\", \"coordinates\": [[[1,2],[3,4],[5,6],[1,2]]]}","geometry_multipoint":"{\"type\": \"MultiPoint\", \"coordinates\": [[1,2]]}","geometry_multiline":"{\"type\": \"MultiLineString\", \"coordinates\": [[[1,2],[3,4]]]}","geometry_multipoly":"{\"type\": \"MultiPolygon\", \"coordinates\": [[[[1,2],[3,4],[5,6],[1,2]]]]}","geometry_collection":"{\"type\": \"GeometryCollection\", \"geometries\": [{\"type\": \"Point\", \"coordinates\": [1,2]}]}"}}}"### + ); + + Ok(()) + } + + fn schema_geojson_geography() -> String { + let schema = indoc! { + r#"model Model { + @@schema("test") + #id(id, String, @id, @default(cuid())) + geography GeoJson @test.Geography(Geometry, 4326) + geography_point GeoJson @test.Geography(Point, 4326) + geography_line GeoJson @test.Geography(LineString, 4326) + geography_poly GeoJson @test.Geography(Polygon, 4326) + geography_multipoint GeoJson @test.Geography(MultiPoint, 4326) + geography_multiline GeoJson @test.Geography(MultiLineString, 4326) + geography_multipoly GeoJson @test.Geography(MultiPolygon, 4326) + geography_collection GeoJson @test.Geography(GeometryCollection, 4326) + }"# + }; + + schema.to_owned() + } + + // "PostGIS common geometry types" should "work" with GeoJSON + #[connector_test( + only(Postgres("15-postgis"), CockroachDb), + schema(schema_geojson_geography), + db_schemas("public", "test") + )] + async fn native_geojson_geography(runner: Runner) -> TestResult<()> { + insta::assert_snapshot!( + run_query!(&runner, r#"mutation { + createOneModel( + data: { + geography: "{\"type\":\"Point\",\"coordinates\":[1,2]}" + geography_point: "{\"type\":\"Point\",\"coordinates\":[1,2]}" + geography_line: "{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}" + geography_poly: "{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}" + geography_multipoint: "{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}" + geography_multiline: "{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}" + geography_multipoly: "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}" + geography_collection: "{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}" + } + ) { + geography + geography_point + geography_line + geography_poly + geography_multipoint + geography_multiline + geography_multipoly + geography_collection + } + }"#), + @r###"{"data":{"createOneModel":{"geography":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geography_point":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geography_line":"{\"type\": \"LineString\", \"coordinates\": [[1,2],[3,4]]}","geography_poly":"{\"type\": \"Polygon\", \"coordinates\": [[[1,2],[3,4],[5,6],[1,2]]]}","geography_multipoint":"{\"type\": \"MultiPoint\", \"coordinates\": [[1,2]]}","geography_multiline":"{\"type\": \"MultiLineString\", \"coordinates\": [[[1,2],[3,4]]]}","geography_multipoly":"{\"type\": \"MultiPolygon\", \"coordinates\": [[[[1,2],[3,4],[5,6],[1,2]]]]}","geography_collection":"{\"type\": \"GeometryCollection\", \"geometries\": [{\"type\": \"Point\", \"coordinates\": [1,2]}]}"}}}"### + ); + + Ok(()) + } } diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sql_server.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sql_server.rs index 880dd687efd6..38dabaec7fa0 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sql_server.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sql_server.rs @@ -361,8 +361,10 @@ mod sql_server { let schema = indoc! { r#"model Model { #id(id, String, @id, @default(cuid())) - xml String @test.Xml - uuid String @test.UniqueIdentifier + xml String @test.Xml + uuid String @test.UniqueIdentifier + geom Geometry @test.Geometry + geog Geometry @test.Geography }"# }; @@ -378,13 +380,17 @@ mod sql_server { data: { xml: "purr" uuid: "ab309dfd-d041-4110-b162-75d7b95fe989" + geom: "SRID=4326;POINT(1 2)" + geog: "SRID=4326;POINT(1 2)" } ) { xml uuid + geom + geog } }"#), - @r###"{"data":{"createOneModel":{"xml":"purr","uuid":"ab309dfd-d041-4110-b162-75d7b95fe989"}}}"### + @r###"{"data":{"createOneModel":{"xml":"purr","uuid":"ab309dfd-d041-4110-b162-75d7b95fe989","geom":"SRID=4326;POINT (1 2)","geog":"SRID=4326;POINT (1 2)"}}}"### ); Ok(()) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sqlite.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sqlite.rs new file mode 100644 index 000000000000..10fd173a7c99 --- /dev/null +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sqlite.rs @@ -0,0 +1,160 @@ +use query_engine_tests::*; + +#[test_suite(only(Sqlite))] +mod sqlite { + use indoc::indoc; + use query_engine_tests::run_query; + + fn schema_ewkt_geometry() -> String { + let schema = indoc! { + r#"model Model { + #id(id, String, @id, @default(cuid())) + geometry Geometry @test.Geometry(Geometry) + geometry_point Geometry @test.Geometry(Point) + geometry_line Geometry @test.Geometry(LineString) + geometry_poly Geometry @test.Geometry(Polygon) + geometry_multipoint Geometry @test.Geometry(MultiPoint) + geometry_multiline Geometry @test.Geometry(MultiLineString) + geometry_multipoly Geometry @test.Geometry(MultiPolygon) + geometry_collection Geometry @test.Geometry(GeometryCollection) + }"# + }; + + schema.to_owned() + } + + // "Spatialite common geometry types" should "work" + #[connector_test(schema(schema_ewkt_geometry))] + async fn native_ewkt_geometry(runner: Runner) -> TestResult<()> { + insta::assert_snapshot!( + run_query!(&runner, r#"mutation { + createOneModel( + data: { + geometry: "POINT(1 2)" + geometry_point: "POINT(1 2)" + geometry_line: "LINESTRING(1 2,3 4)" + geometry_poly: "POLYGON((1 2,3 4,5 6,1 2))" + geometry_multipoint: "MULTIPOINT(1 2)" + geometry_multiline: "MULTILINESTRING((1 2,3 4))" + geometry_multipoly: "MULTIPOLYGON(((1 2,3 4,5 6,1 2)))" + geometry_collection: "GEOMETRYCOLLECTION(POINT(1 2))" + } + ) { + geometry + geometry_point + geometry_line + geometry_poly + geometry_multipoint + geometry_multiline + geometry_multipoly + geometry_collection + } + }"#), + @r###"{"data":{"createOneModel":{"geometry":"POINT(1 2)","geometry_point":"POINT(1 2)","geometry_line":"LINESTRING(1 2,3 4)","geometry_poly":"POLYGON((1 2,3 4,5 6,1 2))","geometry_multipoint":"MULTIPOINT(1 2)","geometry_multiline":"MULTILINESTRING((1 2,3 4))","geometry_multipoly":"MULTIPOLYGON(((1 2,3 4,5 6,1 2)))","geometry_collection":"GEOMETRYCOLLECTION(POINT(1 2))"}}}"### + ); + + Ok(()) + } + + fn schema_ewkt_geometry_srid() -> String { + let schema = indoc! { + r#"model Model { + #id(id, String, @id, @default(cuid())) + geometry Geometry @test.Geometry(Geometry, 3857) + geometry_point Geometry @test.Geometry(Point, 3857) + geometry_line Geometry @test.Geometry(LineString, 3857) + geometry_poly Geometry @test.Geometry(Polygon, 3857) + geometry_multipoint Geometry @test.Geometry(MultiPoint, 3857) + geometry_multiline Geometry @test.Geometry(MultiLineString, 3857) + geometry_multipoly Geometry @test.Geometry(MultiPolygon, 3857) + geometry_collection Geometry @test.Geometry(GeometryCollection, 3857) + }"# + }; + + schema.to_owned() + } + + // "Spatialite common geometry types with srid" should "work" + #[connector_test(schema(schema_ewkt_geometry_srid))] + async fn native_geometry_srid(runner: Runner) -> TestResult<()> { + insta::assert_snapshot!( + run_query!(&runner, r#"mutation { + createOneModel( + data: { + geometry: "SRID=3857;POINT(1 2)" + geometry_point: "SRID=3857;POINT(1 2)" + geometry_line: "SRID=3857;LINESTRING(1 2,3 4)" + geometry_poly: "SRID=3857;POLYGON((1 2,3 4,5 6,1 2))" + geometry_multipoint: "SRID=3857;MULTIPOINT(1 2)" + geometry_multiline: "SRID=3857;MULTILINESTRING((1 2,3 4))" + geometry_multipoly: "SRID=3857;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))" + geometry_collection: "SRID=3857;GEOMETRYCOLLECTION(POINT(1 2))" + } + ) { + geometry + geometry_point + geometry_line + geometry_poly + geometry_multipoint + geometry_multiline + geometry_multipoly + geometry_collection + } + }"#), + @r###"{"data":{"createOneModel":{"geometry":"SRID=3857;POINT(1 2)","geometry_point":"SRID=3857;POINT(1 2)","geometry_line":"SRID=3857;LINESTRING(1 2,3 4)","geometry_poly":"SRID=3857;POLYGON((1 2,3 4,5 6,1 2))","geometry_multipoint":"SRID=3857;MULTIPOINT(1 2)","geometry_multiline":"SRID=3857;MULTILINESTRING((1 2,3 4))","geometry_multipoly":"SRID=3857;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))","geometry_collection":"SRID=3857;GEOMETRYCOLLECTION(POINT(1 2))"}}}"### + ); + + Ok(()) + } + + fn schema_geojson_geometry() -> String { + let schema = indoc! { + r#"model Model { + #id(id, String, @id, @default(cuid())) + geometry GeoJson @test.Geometry(Geometry, 4326) + geometry_point GeoJson @test.Geometry(Point, 4326) + geometry_line GeoJson @test.Geometry(LineString, 4326) + geometry_poly GeoJson @test.Geometry(Polygon, 4326) + geometry_multipoint GeoJson @test.Geometry(MultiPoint, 4326) + geometry_multiline GeoJson @test.Geometry(MultiLineString, 4326) + geometry_multipoly GeoJson @test.Geometry(MultiPolygon, 4326) + geometry_collection GeoJson @test.Geometry(GeometryCollection, 4326) + }"# + }; + + schema.to_owned() + } + + // "Spatialite geometry types" should "work" with GeoJSON + #[connector_test(schema(schema_geojson_geometry))] + async fn native_geojson_geometry(runner: Runner) -> TestResult<()> { + insta::assert_snapshot!( + run_query!(&runner, r#"mutation { + createOneModel( + data: { + geometry: "{\"type\":\"Point\",\"coordinates\":[1,2]}" + geometry_point: "{\"type\":\"Point\",\"coordinates\":[1,2]}" + geometry_line: "{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}" + geometry_poly: "{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}" + geometry_multipoint: "{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}" + geometry_multiline: "{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}" + geometry_multipoly: "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}" + geometry_collection: "{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}" + } + ) { + geometry + geometry_point + geometry_line + geometry_poly + geometry_multipoint + geometry_multiline + geometry_multipoly + geometry_collection + } + }"#), + @r###"{"data":{"createOneModel":{"geometry":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geometry_point":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geometry_line":"{\"type\": \"LineString\", \"coordinates\": [[1,2],[3,4]]}","geometry_poly":"{\"type\": \"Polygon\", \"coordinates\": [[[1,2],[3,4],[5,6],[1,2]]]}","geometry_multipoint":"{\"type\": \"MultiPoint\", \"coordinates\": [[1,2]]}","geometry_multiline":"{\"type\": \"MultiLineString\", \"coordinates\": [[[1,2],[3,4]]]}","geometry_multipoly":"{\"type\": \"MultiPolygon\", \"coordinates\": [[[[1,2],[3,4],[5,6],[1,2]]]]}","geometry_collection":"{\"type\": \"GeometryCollection\", \"geometries\": [{\"type\": \"Point\", \"coordinates\": [1,2]}]}"}}}"### + ); + + Ok(()) + } +} diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs index 1507ea0c082b..d53b98daf871 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs @@ -424,3 +424,36 @@ mod mapped_create { Ok(()) } } + +#[test_suite( + schema(geometry_opt), + capabilities(GeoJsonGeometry), + exclude(Postgres(9, 10, 11, 12, 13, 14, 15, "pgbouncer")) +)] +mod geometry_create { + use query_engine_tests::run_query; + + #[connector_test] + async fn create_geometry(runner: Runner) -> TestResult<()> { + // TODO@geometry: ideally, make geojson generation consistent with SQL connectors + match_connector_result!( + &runner, + r#"mutation { createOneTestModel(data: { id: 1, geometry: "{\"type\": \"Point\", \"coordinates\": [1,2]}" }) { geometry }}"#, + // MongoDB excludes undefined fields + MongoDb(_) => vec![r#"{"data":{"createOneTestModel":{"geometry":"{\"type\":\"Point\",\"coordinates\":[1,2]}"}}}"#], + _ => vec![r#"{"data":{"createOneTestModel":{"geometry":"{\"type\": \"Point\", \"coordinates\": [1,2]}"}}}"#] + ); + + insta::assert_snapshot!( + run_query!(&runner, r#"mutation { createOneTestModel(data: { id: 2, geometry: null }) { geometry }}"#), + @r###"{"data":{"createOneTestModel":{"geometry":null}}}"### + ); + + insta::assert_snapshot!( + run_query!(&runner, r#"mutation { createOneTestModel(data: { id: 3 }) { geometry }}"#), + @r###"{"data":{"createOneTestModel":{"geometry":null}}}"### + ); + + Ok(()) + } +} diff --git a/query-engine/connector-test-kit-rs/query-tests-setup/src/connector_tag/mod.rs b/query-engine/connector-test-kit-rs/query-tests-setup/src/connector_tag/mod.rs index 6cc6120f71c8..a3b84a9173a8 100644 --- a/query-engine/connector-test-kit-rs/query-tests-setup/src/connector_tag/mod.rs +++ b/query-engine/connector-test-kit-rs/query-tests-setup/src/connector_tag/mod.rs @@ -108,6 +108,9 @@ pub(crate) fn connection_string( Some(PostgresVersion::V15) if is_ci => { format!("postgresql://postgres:prisma@test-db-postgres-15:5432/{database}") } + Some(PostgresVersion::V15PostGIS) if is_ci => { + format!("postgresql://postgres:prisma@test-db-postgres-15:5432/{database}") + } Some(PostgresVersion::PgBouncer) if is_ci => { format!("postgresql://postgres:prisma@test-db-pgbouncer:6432/{database}&pgbouncer=true") } @@ -121,6 +124,7 @@ pub(crate) fn connection_string( } Some(PostgresVersion::V14) => format!("postgresql://postgres:prisma@127.0.0.1:5437/{database}"), Some(PostgresVersion::V15) => format!("postgresql://postgres:prisma@127.0.0.1:5438/{database}"), + Some(PostgresVersion::V15PostGIS) => format!("postgresql://postgres:prisma@127.0.0.1:5439/{database}"), Some(PostgresVersion::PgBouncer) => { format!("postgresql://postgres:prisma@127.0.0.1:6432/db?{database}&pgbouncer=true") } diff --git a/query-engine/connector-test-kit-rs/query-tests-setup/src/connector_tag/postgres.rs b/query-engine/connector-test-kit-rs/query-tests-setup/src/connector_tag/postgres.rs index 42d0a8c7afdc..0fbcc447be2f 100644 --- a/query-engine/connector-test-kit-rs/query-tests-setup/src/connector_tag/postgres.rs +++ b/query-engine/connector-test-kit-rs/query-tests-setup/src/connector_tag/postgres.rs @@ -35,6 +35,7 @@ pub enum PostgresVersion { V13, V14, V15, + V15PostGIS, PgBouncer, NeonJs, PgJs, @@ -52,6 +53,7 @@ impl TryFrom<&str> for PostgresVersion { "13" => Self::V13, "14" => Self::V14, "15" => Self::V15, + "15-postgis" => Self::V15PostGIS, "pgbouncer" => Self::PgBouncer, "neon.js" => Self::NeonJs, "pg.js" => Self::PgJs, @@ -72,6 +74,7 @@ impl ToString for PostgresVersion { PostgresVersion::V13 => "13", PostgresVersion::V14 => "14", PostgresVersion::V15 => "15", + PostgresVersion::V15PostGIS => "15-postgis", PostgresVersion::PgBouncer => "pgbouncer", PostgresVersion::NeonJs => "neon.js", PostgresVersion::PgJs => "pg.js", diff --git a/query-engine/connector-test-kit-rs/test-configs/postgis15 b/query-engine/connector-test-kit-rs/test-configs/postgis15 new file mode 100644 index 000000000000..8eeacbfe705e --- /dev/null +++ b/query-engine/connector-test-kit-rs/test-configs/postgis15 @@ -0,0 +1,3 @@ +{ + "connector": "postgres", + "version": "15-postgis"} diff --git a/query-engine/connectors/mongodb-query-connector/src/filter.rs b/query-engine/connectors/mongodb-query-connector/src/filter.rs index 64bdadafd6a9..b60179788069 100644 --- a/query-engine/connectors/mongodb-query-connector/src/filter.rs +++ b/query-engine/connectors/mongodb-query-connector/src/filter.rs @@ -242,6 +242,22 @@ impl MongoFilterVisitor { } _ => unimplemented!("Only equality JSON filtering is supported on MongoDB."), }, + ScalarCondition::GeometryWithin(_val) => { + unimplemented!("Geometry filtering is not yet supported on MongoDB") + // doc! { "$geoWithin": [&field_name, self.coerce_to_bson_for_filter(field, val)?] } + } + ScalarCondition::GeometryNotWithin(_val) => { + unimplemented!("Geometry filtering is not yet supported on MongoDB") + // doc! { "$not": { "$geoWithin": [&field_name, self.coerce_to_bson_for_filter(field, val)?] } } + } + ScalarCondition::GeometryIntersects(_val) => { + unimplemented!("Geometry filtering is not yet supported on MongoDB") + // doc! { "$geoIntersects": [&field_name, self.coerce_to_bson_for_filter(field, val)?] } + } + ScalarCondition::GeometryNotIntersects(_val) => { + unimplemented!("Geometry filtering is not yet supported on MongoDB") + // doc! { "$not" : { "$geoIntersects": [&field_name, self.coerce_to_bson_for_filter(field, val)?] } } + } ScalarCondition::IsSet(is_set) => render_is_set(&field_name, is_set), ScalarCondition::Search(_, _) => unimplemented!("Full-text search is not supported yet on MongoDB"), ScalarCondition::NotSearch(_, _) => unimplemented!("Full-text search is not supported yet on MongoDB"), @@ -381,6 +397,18 @@ impl MongoFilterVisitor { ScalarCondition::JsonCompare(_) => Err(MongoError::Unsupported( "JSON filtering is not yet supported on MongoDB".to_string(), )), + ScalarCondition::GeometryWithin(_) => Err(MongoError::Unsupported( + "Geometry Contains insensitive filtering is not yet supported on MongoDB".to_string(), + )), + ScalarCondition::GeometryNotWithin(_) => Err(MongoError::Unsupported( + "Geometry NotContains insensitive filtering is not yet supported on MongoDB".to_string(), + )), + ScalarCondition::GeometryIntersects(_) => Err(MongoError::Unsupported( + "Geometry Intersects insensitive filtering is not yet supported on MongoDB".to_string(), + )), + ScalarCondition::GeometryNotIntersects(_) => Err(MongoError::Unsupported( + "Geometry NotIntersects insensitive filtering is not yet supported on MongoDB".to_string(), + )), ScalarCondition::Search(_, _) | ScalarCondition::NotSearch(_, _) => Err(MongoError::Unsupported( "Full-text search is not supported yet on MongoDB".to_string(), )), diff --git a/query-engine/connectors/mongodb-query-connector/src/value.rs b/query-engine/connectors/mongodb-query-connector/src/value.rs index cf6812d59b6d..62296447acbc 100644 --- a/query-engine/connectors/mongodb-query-connector/src/value.rs +++ b/query-engine/connectors/mongodb-query-connector/src/value.rs @@ -9,7 +9,8 @@ use itertools::Itertools; use mongodb::bson::{oid::ObjectId, spec::BinarySubtype, Binary, Bson, Document, Timestamp}; use psl::builtin_connectors::MongoDbType; use query_structure::{ - CompositeFieldRef, Field, PrismaValue, RelationFieldRef, ScalarFieldRef, SelectedField, TypeIdentifier, + CompositeFieldRef, Field, GeometryFormat, PrismaValue, RelationFieldRef, ScalarFieldRef, SelectedField, + TypeIdentifier, }; use serde_json::Value; use std::{convert::TryFrom, fmt::Display}; @@ -263,6 +264,15 @@ impl IntoBson for (&TypeIdentifier, PrismaValue) { })? } + // Geometry + (TypeIdentifier::Geometry(GeometryFormat::GeoJSON), PrismaValue::GeoJson(json)) => { + let val: Value = serde_json::from_str(&json)?; + Bson::try_from(val).map_err(|_| MongoError::ConversionError { + from: "Stringified JSON".to_owned(), + to: "Mongo BSON (extJSON)".to_owned(), + })? + } + // List values (typ, PrismaValue::List(vals)) => Bson::Array( vals.into_iter() @@ -374,6 +384,11 @@ fn read_scalar_value(bson: Bson, meta: &ScalarOutputMeta) -> crate::Result PrismaValue::Json(serde_json::to_string(&bson.into_relaxed_extjson())?), + // Geometry + (TypeIdentifier::Geometry(GeometryFormat::GeoJSON), bson @ Bson::Document(_)) => { + PrismaValue::GeoJson(serde_json::to_string(&bson.into_relaxed_extjson())?) + } + (ident, bson) => { return Err(MongoError::ConversionError { from: bson.to_string(), diff --git a/query-engine/connectors/sql-query-connector/Cargo.toml b/query-engine/connectors/sql-query-connector/Cargo.toml index fbe04850164d..c3a84ed28a2d 100644 --- a/query-engine/connectors/sql-query-connector/Cargo.toml +++ b/query-engine/connectors/sql-query-connector/Cargo.toml @@ -30,6 +30,8 @@ cuid = { git = "https://github.com/prisma/cuid-rust", branch = "wasm32-support" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] quaint.workspace = true +regex = "1.9.3" +geozero = "0.10.0" [target.'cfg(target_arch = "wasm32")'.dependencies] quaint = { path = "../../../quaint" } diff --git a/query-engine/connectors/sql-query-connector/src/filter/visitor.rs b/query-engine/connectors/sql-query-connector/src/filter/visitor.rs index 1a71cdd824a8..0a84f0a06fa7 100644 --- a/query-engine/connectors/sql-query-connector/src/filter/visitor.rs +++ b/query-engine/connectors/sql-query-connector/src/filter/visitor.rs @@ -962,6 +962,18 @@ fn default_scalar_filter( comparable.not_matches(query) } + ScalarCondition::GeometryWithin(value) => { + comparable.geometry_within(convert_first_value(fields, value, alias, ctx)) + } + ScalarCondition::GeometryNotWithin(value) => { + comparable.geometry_not_within(convert_first_value(fields, value, alias, ctx)) + } + ScalarCondition::GeometryIntersects(value) => { + comparable.geometry_intersects(convert_first_value(fields, value, alias, ctx)) + } + ScalarCondition::GeometryNotIntersects(value) => { + comparable.geometry_not_intersects(convert_first_value(fields, value, alias, ctx)) + } ScalarCondition::JsonCompare(_) => unreachable!(), ScalarCondition::IsSet(_) => unreachable!(), }; @@ -1142,6 +1154,10 @@ fn insensitive_scalar_filter( comparable.not_matches(query) } + ScalarCondition::GeometryWithin(_) => unreachable!(), + ScalarCondition::GeometryNotWithin(_) => unreachable!(), + ScalarCondition::GeometryIntersects(_) => unreachable!(), + ScalarCondition::GeometryNotIntersects(_) => unreachable!(), ScalarCondition::JsonCompare(_) => unreachable!(), ScalarCondition::IsSet(_) => unreachable!(), }; diff --git a/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs b/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs index 21612e1a6392..d1dfa3d7a500 100644 --- a/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs +++ b/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs @@ -1,8 +1,11 @@ +use std::str::FromStr; + use crate::context::Context; use chrono::Utc; +use geozero::{geojson::GeoJson, ToWkt}; use prisma_value::PrismaValue; use quaint::{ - ast::{EnumName, Value, ValueType}, + ast::{EnumName, GeometryValue, Value, ValueType}, prelude::{EnumVariant, TypeDataLength, TypeFamily}, }; use query_structure::{ScalarField, TypeIdentifier}; @@ -53,6 +56,23 @@ impl ScalarFieldExt for ScalarField { (PrismaValue::Json(s), _) => Value::json(serde_json::from_str::(&s).unwrap()), (PrismaValue::Bytes(b), _) => Value::bytes(b), (PrismaValue::Object(_), _) => unimplemented!(), + (PrismaValue::GeoJson(s), _) => { + let geometry = GeometryValue { + wkt: GeoJson(&s).to_wkt().unwrap(), + srid: 4326, + }; + match self.type_family() { + TypeFamily::Geography(_) => Value::geography(geometry), + _ => Value::geometry(geometry), + } + } + (PrismaValue::Geometry(s), _) => { + let geometry = GeometryValue::from_str(&s).unwrap(); + match self.type_family() { + TypeFamily::Geography(_) => Value::geography(geometry), + _ => Value::geometry(geometry), + } + } (PrismaValue::Null, ident) => match ident { TypeIdentifier::String => Value::null_text(), TypeIdentifier::Float => Value::null_numeric(), @@ -74,6 +94,7 @@ impl ScalarFieldExt for ScalarField { TypeIdentifier::Int => Value::null_int32(), TypeIdentifier::BigInt => Value::null_int64(), TypeIdentifier::Bytes => Value::null_bytes(), + TypeIdentifier::Geometry(_) => Value::null_geometry(), TypeIdentifier::Unsupported => unreachable!("No unsupported field should reach that path"), }, }; @@ -102,6 +123,22 @@ impl ScalarFieldExt for ScalarField { TypeIdentifier::Json => TypeFamily::Text(Some(TypeDataLength::Maximum)), TypeIdentifier::DateTime => TypeFamily::DateTime, TypeIdentifier::Bytes => TypeFamily::Text(parse_scalar_length(self)), + TypeIdentifier::Geometry(_) => { + let type_info = self.native_type().map(|nt| { + let name = nt.name(); + let srid = match nt.args().as_slice() { + [srid] => srid.parse::().ok(), + [_, srid] => srid.parse::().ok(), + _ => None, + }; + (name, srid) + }); + match type_info { + Some(("Geography", srid)) => TypeFamily::Geography(srid), + Some((_, srid)) => TypeFamily::Geometry(srid), + _ => TypeFamily::Geometry(None), + } + } TypeIdentifier::Unsupported => unreachable!("No unsupported field should reach that path"), } } @@ -122,6 +159,9 @@ pub fn convert_lossy<'a>(pv: PrismaValue) -> Value<'a> { PrismaValue::List(l) => Value::array(l.into_iter().map(convert_lossy)), PrismaValue::Json(s) => Value::json(serde_json::from_str(&s).unwrap()), PrismaValue::Bytes(b) => Value::bytes(b), + // TODO@geom: Fix this when we know how to cast GeoJSON to an appropriate DB value + PrismaValue::GeoJson(s) => Value::json(serde_json::from_str(&s).unwrap()), + PrismaValue::Geometry(s) => Value::geometry(GeometryValue::from_str(&s).unwrap()), PrismaValue::Null => Value::null_int32(), // Can't tell which type the null is supposed to be. PrismaValue::Object(_) => unimplemented!(), } diff --git a/query-engine/connectors/sql-query-connector/src/query_builder/read.rs b/query-engine/connectors/sql-query-connector/src/query_builder/read.rs index 3aa91288ea90..3444d929b8c9 100644 --- a/query-engine/connectors/sql-query-connector/src/query_builder/read.rs +++ b/query-engine/connectors/sql-query-connector/src/query_builder/read.rs @@ -4,6 +4,7 @@ use crate::{ }; use connector_interface::{AggregationSelection, RelAggregationSelection}; use itertools::Itertools; +use psl::datamodel_connector::Connector; use quaint::ast::*; use query_structure::*; use tracing::Span; @@ -113,6 +114,14 @@ impl SelectDefinition for QueryArguments { } } +fn get_column_read_expression<'a>(col: Column<'a>, connector: &'a dyn Connector) -> Expression<'a> { + let supports_raw_geom_io = connector.supports_raw_geometry_read(); + match col.type_family { + Some(TypeFamily::Geometry(_) | TypeFamily::Geography(_)) if !supports_raw_geom_io => geom_as_text(col).into(), + _ => col.into(), + } +} + pub(crate) fn get_records( model: &Model, columns: impl Iterator>, @@ -124,10 +133,13 @@ where T: SelectDefinition, { let (select, additional_selection_set) = query.into_select(model, aggr_selections, ctx); - let select = columns.fold(select, |acc, col| acc.column(col)); - - let select = select.append_trace(&Span::current()).add_trace_id(ctx.trace_id); + let select = columns + .map(|c| get_column_read_expression(c, model.dm.schema.connector)) + .fold(select, |acc, col| acc.value(col)) + .append_trace(&Span::current()) + .add_trace_id(ctx.trace_id); + // TODO@geometry: Should we call get_column_read_expression in "additional_selection_set" too ? additional_selection_set .into_iter() .fold(select, |acc, col| acc.value(col)) diff --git a/query-engine/connectors/sql-query-connector/src/query_builder/write.rs b/query-engine/connectors/sql-query-connector/src/query_builder/write.rs index c5bb3e24ddb6..5dd914f5a3b2 100644 --- a/query-engine/connectors/sql-query-connector/src/query_builder/write.rs +++ b/query-engine/connectors/sql-query-connector/src/query_builder/write.rs @@ -31,6 +31,7 @@ pub(crate) fn create_record( insert.value(db_name.to_owned(), field.value(value, ctx)) }); + // TODO@geometry: Should we call geom_as_text in returning statement too ? Insert::from(insert) .returning(selected_fields.as_columns(ctx).map(|c| c.set_is_selected(true))) .append_trace(&Span::current()) diff --git a/query-engine/connectors/sql-query-connector/src/row.rs b/query-engine/connectors/sql-query-connector/src/row.rs index 6f154b1f77dc..a95ab8d859c5 100644 --- a/query-engine/connectors/sql-query-connector/src/row.rs +++ b/query-engine/connectors/sql-query-connector/src/row.rs @@ -2,8 +2,10 @@ use crate::{column_metadata::ColumnMetadata, error::SqlError, value::to_prisma_v use bigdecimal::{BigDecimal, FromPrimitive, ToPrimitive}; use chrono::{DateTime, NaiveDate, Utc}; use connector_interface::{coerce_null_to_zero_value, AggregationResult, AggregationSelection}; +use geozero::wkt::WktStr; +use geozero::ToJson; use quaint::{connector::ResultRow, Value, ValueType}; -use query_structure::{ConversionFailure, FieldArity, PrismaValue, Record, TypeIdentifier}; +use query_structure::{ConversionFailure, FieldArity, GeometryFormat, PrismaValue, Record, TypeIdentifier}; use std::{io, str::FromStr}; use uuid::Uuid; @@ -287,6 +289,29 @@ fn row_value_to_prisma_value(p_value: Value, meta: ColumnMetadata<'_>) -> Result ValueType::Bytes(Some(bytes)) => PrismaValue::Bytes(bytes.into()), _ => return Err(create_error(&p_value)), }, + TypeIdentifier::Geometry(GeometryFormat::EWKT) => match p_value.typed { + value if value.is_null() => PrismaValue::Null, + ValueType::Text(Some(ewkt)) => match ewkt.starts_with("SRID=0;") { + true => PrismaValue::Geometry(ewkt[7..].into()), + false => PrismaValue::Geometry(ewkt.into()), + }, + _ => return Err(create_error(&p_value)), + }, + TypeIdentifier::Geometry(GeometryFormat::GeoJSON) => match p_value.typed { + value if value.is_null() => PrismaValue::Null, + // MySQL @<=5.7 and MSSQL cannot return geometry as GeoJSON, so we must serialize + // the ewkt string back to geojson. However, per specification, GeoJSON geometries + // can only be represented with EPSG:4326 projection. Plus WKT can represent more + // spatial types than GeoJSON can, so this operation may fail. + ValueType::Text(Some(ref ewkt)) => match ewkt.starts_with("SRID=4326;") { + true => WktStr(&ewkt[10..]) + .to_json() + .map(PrismaValue::GeoJson) + .map_err(|_| create_error(&p_value))?, + false => return Err(create_error(&p_value)), + }, + _ => return Err(create_error(&p_value)), + }, TypeIdentifier::Unsupported => unreachable!("No unsupported field should reach that path"), }) } diff --git a/query-engine/connectors/sql-query-connector/src/value.rs b/query-engine/connectors/sql-query-connector/src/value.rs index 0929003955f7..888bcda5525e 100644 --- a/query-engine/connectors/sql-query-connector/src/value.rs +++ b/query-engine/connectors/sql-query-connector/src/value.rs @@ -98,6 +98,10 @@ pub fn to_prisma_value<'a, T: Into>>(qv: T) -> crate::Result s .map(|s| PrismaValue::String(s.into_owned())) .unwrap_or(PrismaValue::Null), + + ValueType::Geometry(s) | ValueType::Geography(s) => s + .map(|s| PrismaValue::Geometry(s.to_string())) + .unwrap_or(PrismaValue::Null), }; Ok(val) diff --git a/query-engine/connectors/sql-query-connector/src/value_ext.rs b/query-engine/connectors/sql-query-connector/src/value_ext.rs index a84c9da0380b..011273f6b1b4 100644 --- a/query-engine/connectors/sql-query-connector/src/value_ext.rs +++ b/query-engine/connectors/sql-query-connector/src/value_ext.rs @@ -28,6 +28,8 @@ impl<'a> IntoTypedJsonExtension for quaint::Value<'a> { quaint::ValueType::DateTime(_) => "datetime", quaint::ValueType::Date(_) => "date", quaint::ValueType::Time(_) => "time", + quaint::ValueType::Geometry(_) => "geometry", + quaint::ValueType::Geography(_) => "geography", quaint::ValueType::Array(_) | quaint::ValueType::EnumArray(_, _) => "array", }; diff --git a/query-engine/core/Cargo.toml b/query-engine/core/Cargo.toml index b23050ab7eec..ec20e7415ae4 100644 --- a/query-engine/core/Cargo.toml +++ b/query-engine/core/Cargo.toml @@ -36,6 +36,7 @@ cuid = { git = "https://github.com/prisma/cuid-rust", branch = "wasm32-support" schema = { path = "../schema" } lru = "0.7.7" enumflags2 = "0.7" +geojson = { version = "0.24.1", default-features = false } pin-project = "1" wasm-bindgen-futures = "0.4" diff --git a/query-engine/core/src/constants.rs b/query-engine/core/src/constants.rs index abf320a2969c..62a29f39cf03 100644 --- a/query-engine/core/src/constants.rs +++ b/query-engine/core/src/constants.rs @@ -9,6 +9,8 @@ pub mod custom_types { pub const DECIMAL: &str = "Decimal"; pub const BYTES: &str = "Bytes"; pub const JSON: &str = "Json"; + pub const EWKT_GEOMETRY: &str = "Geometry"; + pub const GEOJSON: &str = "GeoJson"; pub const ENUM: &str = "Enum"; pub const FIELD_REF: &str = "FieldRef"; diff --git a/query-engine/core/src/query_document/parser.rs b/query-engine/core/src/query_document/parser.rs index 79f30e1bd8b7..55af304aa1a5 100644 --- a/query-engine/core/src/query_document/parser.rs +++ b/query-engine/core/src/query_document/parser.rs @@ -3,6 +3,7 @@ use crate::{executor::get_engine_protocol, schema::*}; use bigdecimal::{BigDecimal, ToPrimitive}; use chrono::prelude::*; use core::fmt; +use geojson::GeoJson; use indexmap::{IndexMap, IndexSet}; use query_structure::{DefaultKind, PrismaValue, ValueGeneratorFn}; use std::{borrow::Cow, convert::TryFrom, rc::Rc, str::FromStr}; @@ -355,6 +356,8 @@ impl QueryDocumentParser { (PrismaValue::Bytes(bytes), ScalarType::Bytes) => Ok(PrismaValue::Bytes(bytes)), (PrismaValue::BigInt(b_int), ScalarType::BigInt) => Ok(PrismaValue::BigInt(b_int)), (PrismaValue::DateTime(s), ScalarType::DateTime) => Ok(PrismaValue::DateTime(s)), + (PrismaValue::GeoJson(s), ScalarType::GeoJson) => Ok(PrismaValue::GeoJson(s)), + (PrismaValue::Geometry(s), ScalarType::Geometry) => Ok(PrismaValue::Geometry(s)), (PrismaValue::Null, ScalarType::Null) => Ok(PrismaValue::Null), // String coercion matchers @@ -374,6 +377,13 @@ impl QueryDocumentParser { .parse_datetime(selection_path, argument_path, s.as_str()) .map(PrismaValue::DateTime), + // WKT imput can hardly be validated, since all database vendors wkt dialect + // differ in subtle ways that make them incompatible. + (PrismaValue::String(s), ScalarType::Geometry) => Ok(PrismaValue::Geometry(s)), + (PrismaValue::Json(s) | PrismaValue::String(s), ScalarType::GeoJson) => Ok(PrismaValue::GeoJson( + self.parse_geojson(selection_path, argument_path, &s).map(|_| s)?, + )), + // Int coercion matchers (PrismaValue::Int(i), ScalarType::Int) => Ok(PrismaValue::Int(i)), (PrismaValue::Int(i), ScalarType::Float) => Ok(PrismaValue::Float(BigDecimal::from(i))), @@ -518,6 +528,18 @@ impl QueryDocumentParser { Ok(PrismaValue::List(prisma_values)) } + fn parse_geojson(&self, selection_path: &Path, argument_path: &Path, s: &str) -> QueryParserResult { + s.parse::().map_err(|err| { + ValidationError::invalid_argument_value( + selection_path.segments(), + argument_path.segments(), + s.to_string(), + "GeoJSON String", + Some(Box::new(err)), + ) + }) + } + fn parse_json(&self, selection_path: &Path, argument_path: &Path, s: &str) -> QueryParserResult { serde_json::from_str(s).map_err(|err| { ValidationError::invalid_argument_value( @@ -885,6 +907,8 @@ pub(crate) mod conversions { format!("({})", itertools::join(v.iter().map(prisma_value_to_type_name), ", ")) } PrismaValue::Json(_) => "JSON".to_string(), + PrismaValue::GeoJson(_) => "GeoJSON".to_string(), + PrismaValue::Geometry(_) => "EWKTGeometry".to_string(), PrismaValue::Object(_) => "Object".to_string(), PrismaValue::Null => "Null".to_string(), PrismaValue::DateTime(_) => "DateTime".to_string(), diff --git a/query-engine/core/src/query_graph_builder/extractors/filters/scalar.rs b/query-engine/core/src/query_graph_builder/extractors/filters/scalar.rs index ac84ce06aa21..2f1ec3dc46fc 100644 --- a/query-engine/core/src/query_graph_builder/extractors/filters/scalar.rs +++ b/query-engine/core/src/query_graph_builder/extractors/filters/scalar.rs @@ -174,6 +174,24 @@ impl<'a> ScalarFilterParser<'a> { filters::HAS_SOME => Ok(vec![field.contains_some_element(self.as_condition_list_value(input)?)]), filters::IS_EMPTY => Ok(vec![field.is_empty_list(input.try_into()?)]), + // Geometry-specific filters + filters::GEO_WITHIN => { + if self.reverse() { + Ok(vec![field.geometry_not_within(self.as_condition_value(input, false)?)]) + } else { + Ok(vec![field.geometry_within(self.as_condition_value(input, false)?)]) + } + } + filters::GEO_INTERSECTS => { + if self.reverse() { + Ok(vec![ + field.geometry_not_intersects(self.as_condition_value(input, false)?) + ]) + } else { + Ok(vec![field.geometry_intersects(self.as_condition_value(input, false)?)]) + } + } + // Aggregation filters aggregations::UNDERSCORE_COUNT => self.aggregation_filter(input, Filter::count, true), aggregations::UNDERSCORE_AVG => self.aggregation_filter(input, Filter::average, false), diff --git a/query-engine/core/src/response_ir/internal.rs b/query-engine/core/src/response_ir/internal.rs index 7becb19e768b..6df340075f95 100644 --- a/query-engine/core/src/response_ir/internal.rs +++ b/query-engine/core/src/response_ir/internal.rs @@ -573,6 +573,8 @@ fn convert_prisma_value_graphql_protocol( (ScalarType::DateTime, PrismaValue::DateTime(dt)) => PrismaValue::DateTime(dt), (ScalarType::UUID, PrismaValue::Uuid(u)) => PrismaValue::Uuid(u), (ScalarType::Bytes, PrismaValue::Bytes(b)) => PrismaValue::Bytes(b), + (ScalarType::Geometry, PrismaValue::Geometry(s)) => PrismaValue::Geometry(s), + (ScalarType::GeoJson, PrismaValue::GeoJson(s)) => PrismaValue::GeoJson(s), // The Decimal type doesn't have a corresponding PrismaValue variant. We need to serialize it // to String so that client can deserialize it as Decimal again. @@ -616,6 +618,12 @@ fn convert_prisma_value_json_protocol( (ScalarType::Bytes, PrismaValue::Bytes(x)) => { custom_types::make_object(custom_types::BYTES, PrismaValue::Bytes(x)) } + (ScalarType::Geometry, PrismaValue::Geometry(x)) => { + custom_types::make_object(custom_types::EWKT_GEOMETRY, PrismaValue::Geometry(x)) + } + (ScalarType::GeoJson, PrismaValue::GeoJson(x)) => { + custom_types::make_object(custom_types::GEOJSON, PrismaValue::GeoJson(x)) + } // Identity matchers (ScalarType::String, PrismaValue::String(x)) => PrismaValue::String(x), diff --git a/query-engine/dmmf/src/ast_builders/datamodel_ast_builder.rs b/query-engine/dmmf/src/ast_builders/datamodel_ast_builder.rs index c367695150f6..4e670b5092c7 100644 --- a/query-engine/dmmf/src/ast_builders/datamodel_ast_builder.rs +++ b/query-engine/dmmf/src/ast_builders/datamodel_ast_builder.rs @@ -262,6 +262,8 @@ fn prisma_value_to_serde(value: &PrismaValue) -> serde_json::Value { PrismaValue::Null => serde_json::Value::Null, PrismaValue::Uuid(val) => serde_json::Value::String(val.to_string()), PrismaValue::Json(val) => serde_json::Value::String(val.to_string()), + PrismaValue::GeoJson(val) => serde_json::Value::String(val.to_string()), + PrismaValue::Geometry(val) => serde_json::Value::String(val.to_string()), PrismaValue::List(value_vec) => serde_json::Value::Array(value_vec.iter().map(prisma_value_to_serde).collect()), PrismaValue::Bytes(b) => serde_json::Value::String(encode_bytes(b)), PrismaValue::Object(pairs) => { diff --git a/query-engine/dmmf/src/ast_builders/schema_ast_builder/type_renderer.rs b/query-engine/dmmf/src/ast_builders/schema_ast_builder/type_renderer.rs index dd4f26660440..cc70a239a428 100644 --- a/query-engine/dmmf/src/ast_builders/schema_ast_builder/type_renderer.rs +++ b/query-engine/dmmf/src/ast_builders/schema_ast_builder/type_renderer.rs @@ -49,6 +49,8 @@ pub(super) fn render_output_type<'a>(output_type: &OutputType<'a>, ctx: &mut Ren ScalarType::UUID => "UUID", ScalarType::JsonList => "Json", ScalarType::Bytes => "Bytes", + ScalarType::GeoJson => "GeoJson", + ScalarType::Geometry => "Geometry", }; DmmfTypeReference { diff --git a/query-engine/query-structure/src/field/mod.rs b/query-engine/query-structure/src/field/mod.rs index 45d529c56abf..357727c72609 100644 --- a/query-engine/query-structure/src/field/mod.rs +++ b/query-engine/query-structure/src/field/mod.rs @@ -134,6 +134,12 @@ impl Field { } } +#[derive(Clone, Debug, PartialEq, Eq, Hash, Copy)] +pub enum GeometryFormat { + EWKT, + GeoJSON, +} + #[derive(Clone, Debug, PartialEq, Eq, Hash, Copy)] #[allow(clippy::upper_case_acronyms)] pub enum TypeIdentifier { @@ -148,6 +154,7 @@ pub enum TypeIdentifier { Json, DateTime, Bytes, + Geometry(GeometryFormat), Unsupported, } @@ -175,6 +182,8 @@ impl TypeIdentifier { TypeIdentifier::Json => "Json".into(), TypeIdentifier::DateTime => "DateTime".into(), TypeIdentifier::Bytes => "Bytes".into(), + TypeIdentifier::Geometry(GeometryFormat::GeoJSON) => "GeoJson".into(), + TypeIdentifier::Geometry(GeometryFormat::EWKT) => "Geometry".into(), TypeIdentifier::Unsupported => "Unsupported".into(), } } @@ -248,6 +257,8 @@ impl From for TypeIdentifier { ScalarType::Json => Self::Json, ScalarType::Decimal => Self::Decimal, ScalarType::Bytes => Self::Bytes, + ScalarType::Geometry => Self::Geometry(GeometryFormat::EWKT), + ScalarType::GeoJson => Self::Geometry(GeometryFormat::GeoJSON), } } } diff --git a/query-engine/query-structure/src/field/scalar.rs b/query-engine/query-structure/src/field/scalar.rs index b8ef8ab204e2..af854944654a 100644 --- a/query-engine/query-structure/src/field/scalar.rs +++ b/query-engine/query-structure/src/field/scalar.rs @@ -62,6 +62,10 @@ impl ScalarField { self.type_identifier().is_numeric() } + pub fn is_geometry(&self) -> bool { + matches!(self.type_identifier(), TypeIdentifier::Geometry(_)) + } + pub fn container(&self) -> ParentContainer { match self.id { ScalarFieldId::InModel(id) => self.dm.find_model_by_id(self.dm.walk(id).model().id).into(), @@ -259,6 +263,7 @@ pub fn dml_default_kind(default_value: &ast::Expression, scalar_type: Option unreachable!("{:?}", other), } } diff --git a/query-engine/query-structure/src/filter/compare.rs b/query-engine/query-structure/src/filter/compare.rs index 7757965050ad..03d66566c49e 100644 --- a/query-engine/query-structure/src/filter/compare.rs +++ b/query-engine/query-structure/src/filter/compare.rs @@ -61,6 +61,22 @@ pub trait ScalarCompare { where T: Into; + fn geometry_within(&self, val: T) -> Filter + where + T: Into; + + fn geometry_not_within(&self, val: T) -> Filter + where + T: Into; + + fn geometry_intersects(&self, val: T) -> Filter + where + T: Into; + + fn geometry_not_intersects(&self, val: T) -> Filter + where + T: Into; + fn search(&self, val: T) -> Filter where T: Into; diff --git a/query-engine/query-structure/src/filter/scalar/compare.rs b/query-engine/query-structure/src/filter/scalar/compare.rs index efbbb370f664..063eabca3448 100644 --- a/query-engine/query-structure/src/filter/scalar/compare.rs +++ b/query-engine/query-structure/src/filter/scalar/compare.rs @@ -199,6 +199,50 @@ impl ScalarCompare for ScalarFieldRef { mode: QueryMode::Default, }) } + + fn geometry_within(&self, val: T) -> Filter + where + T: Into, + { + Filter::from(ScalarFilter { + projection: ScalarProjection::Single(self.clone()), + condition: ScalarCondition::GeometryWithin(val.into()), + mode: QueryMode::Default, + }) + } + + fn geometry_not_within(&self, val: T) -> Filter + where + T: Into, + { + Filter::from(ScalarFilter { + projection: ScalarProjection::Single(self.clone()), + condition: ScalarCondition::GeometryNotWithin(val.into()), + mode: QueryMode::Default, + }) + } + + fn geometry_intersects(&self, val: T) -> Filter + where + T: Into, + { + Filter::from(ScalarFilter { + projection: ScalarProjection::Single(self.clone()), + condition: ScalarCondition::GeometryIntersects(val.into()), + mode: QueryMode::Default, + }) + } + + fn geometry_not_intersects(&self, val: T) -> Filter + where + T: Into, + { + Filter::from(ScalarFilter { + projection: ScalarProjection::Single(self.clone()), + condition: ScalarCondition::GeometryNotIntersects(val.into()), + mode: QueryMode::Default, + }) + } } impl ScalarCompare for ModelProjection { @@ -399,6 +443,50 @@ impl ScalarCompare for ModelProjection { mode: QueryMode::Default, }) } + + fn geometry_within(&self, val: T) -> Filter + where + T: Into, + { + Filter::from(ScalarFilter { + projection: ScalarProjection::Compound(self.scalar_fields().collect()), + condition: ScalarCondition::GeometryWithin(val.into()), + mode: QueryMode::Default, + }) + } + + fn geometry_not_within(&self, val: T) -> Filter + where + T: Into, + { + Filter::from(ScalarFilter { + projection: ScalarProjection::Compound(self.scalar_fields().collect()), + condition: ScalarCondition::GeometryNotWithin(val.into()), + mode: QueryMode::Default, + }) + } + + fn geometry_intersects(&self, val: T) -> Filter + where + T: Into, + { + Filter::from(ScalarFilter { + projection: ScalarProjection::Compound(self.scalar_fields().collect()), + condition: ScalarCondition::GeometryIntersects(val.into()), + mode: QueryMode::Default, + }) + } + + fn geometry_not_intersects(&self, val: T) -> Filter + where + T: Into, + { + Filter::from(ScalarFilter { + projection: ScalarProjection::Compound(self.scalar_fields().collect()), + condition: ScalarCondition::GeometryNotIntersects(val.into()), + mode: QueryMode::Default, + }) + } } impl ScalarCompare for FieldSelection { @@ -599,4 +687,48 @@ impl ScalarCompare for FieldSelection { mode: QueryMode::Default, }) } + + fn geometry_within(&self, val: T) -> Filter + where + T: Into, + { + Filter::from(ScalarFilter { + projection: ScalarProjection::Compound(self.as_scalar_fields().expect("Todo composites in filters.")), + condition: ScalarCondition::GeometryWithin(val.into()), + mode: QueryMode::Default, + }) + } + + fn geometry_not_within(&self, val: T) -> Filter + where + T: Into, + { + Filter::from(ScalarFilter { + projection: ScalarProjection::Compound(self.as_scalar_fields().expect("Todo composites in filters.")), + condition: ScalarCondition::GeometryNotWithin(val.into()), + mode: QueryMode::Default, + }) + } + + fn geometry_intersects(&self, val: T) -> Filter + where + T: Into, + { + Filter::from(ScalarFilter { + projection: ScalarProjection::Compound(self.as_scalar_fields().expect("Todo composites in filters.")), + condition: ScalarCondition::GeometryIntersects(val.into()), + mode: QueryMode::Default, + }) + } + + fn geometry_not_intersects(&self, val: T) -> Filter + where + T: Into, + { + Filter::from(ScalarFilter { + projection: ScalarProjection::Compound(self.as_scalar_fields().expect("Todo composites in filters.")), + condition: ScalarCondition::GeometryNotIntersects(val.into()), + mode: QueryMode::Default, + }) + } } diff --git a/query-engine/query-structure/src/filter/scalar/condition/mod.rs b/query-engine/query-structure/src/filter/scalar/condition/mod.rs index ff32d3d52219..27b1b5739ecb 100644 --- a/query-engine/query-structure/src/filter/scalar/condition/mod.rs +++ b/query-engine/query-structure/src/filter/scalar/condition/mod.rs @@ -22,6 +22,10 @@ pub enum ScalarCondition { In(ConditionListValue), NotIn(ConditionListValue), JsonCompare(JsonCondition), + GeometryWithin(ConditionValue), + GeometryNotWithin(ConditionValue), + GeometryIntersects(ConditionValue), + GeometryNotIntersects(ConditionValue), Search(ConditionValue, Vec), NotSearch(ConditionValue, Vec), IsSet(bool), @@ -61,6 +65,10 @@ impl ScalarCondition { target_type: json_compare.target_type, }) } + Self::GeometryWithin(v) => Self::GeometryNotWithin(v), + Self::GeometryNotWithin(v) => Self::GeometryWithin(v), + Self::GeometryIntersects(v) => Self::GeometryNotIntersects(v), + Self::GeometryNotIntersects(v) => Self::GeometryIntersects(v), Self::Search(v, fields) => Self::NotSearch(v, fields), Self::NotSearch(v, fields) => Self::Search(v, fields), Self::IsSet(v) => Self::IsSet(!v), @@ -87,6 +95,10 @@ impl ScalarCondition { ScalarCondition::In(v) => v.as_field_ref(), ScalarCondition::NotIn(v) => v.as_field_ref(), ScalarCondition::JsonCompare(json_cond) => json_cond.condition.as_field_ref(), + ScalarCondition::GeometryWithin(v) => v.as_field_ref(), + ScalarCondition::GeometryNotWithin(v) => v.as_field_ref(), + ScalarCondition::GeometryIntersects(v) => v.as_field_ref(), + ScalarCondition::GeometryNotIntersects(v) => v.as_field_ref(), ScalarCondition::Search(v, _) => v.as_field_ref(), ScalarCondition::NotSearch(v, _) => v.as_field_ref(), ScalarCondition::IsSet(_) => None, diff --git a/query-engine/query-structure/src/prisma_value_ext.rs b/query-engine/query-structure/src/prisma_value_ext.rs index 09e052ea844b..9d386531eab1 100644 --- a/query-engine/query-structure/src/prisma_value_ext.rs +++ b/query-engine/query-structure/src/prisma_value_ext.rs @@ -1,5 +1,5 @@ use super::{PrismaValue, TypeIdentifier}; -use crate::DomainError; +use crate::{DomainError, GeometryFormat}; use bigdecimal::ToPrimitive; pub(crate) trait PrismaValueExtensions { @@ -23,6 +23,8 @@ impl PrismaValueExtensions for PrismaValue { (val @ PrismaValue::BigInt(_), TypeIdentifier::BigInt) => val, (val @ PrismaValue::Bytes(_), TypeIdentifier::Bytes) => val, (val @ PrismaValue::Json(_), TypeIdentifier::Json) => val, + (val @ PrismaValue::Geometry(_), TypeIdentifier::Geometry(GeometryFormat::EWKT)) => val, + (val @ PrismaValue::GeoJson(_), TypeIdentifier::Geometry(GeometryFormat::GeoJSON)) => val, // Valid String coercions (PrismaValue::Int(i), TypeIdentifier::String) => PrismaValue::String(format!("{i}")), diff --git a/query-engine/request-handlers/src/protocols/graphql/schema_renderer/type_renderer.rs b/query-engine/request-handlers/src/protocols/graphql/schema_renderer/type_renderer.rs index 7b4d0a370da7..4d3b3e7b4471 100644 --- a/query-engine/request-handlers/src/protocols/graphql/schema_renderer/type_renderer.rs +++ b/query-engine/request-handlers/src/protocols/graphql/schema_renderer/type_renderer.rs @@ -47,6 +47,8 @@ impl<'a> GqlTypeRenderer<'a> { ScalarType::UUID => "UUID", ScalarType::JsonList => "Json", ScalarType::Bytes => "Bytes", + ScalarType::GeoJson => "GeoJson", + ScalarType::Geometry => "Geometry", ScalarType::Null => unreachable!("Null types should not be picked for GQL rendering."), }; @@ -85,6 +87,8 @@ impl<'a> GqlTypeRenderer<'a> { ScalarType::UUID => "UUID", ScalarType::JsonList => "Json", ScalarType::Bytes => "Bytes", + ScalarType::GeoJson => "GeoJson", + ScalarType::Geometry => "Geometry", ScalarType::Null => unreachable!("Null types should not be picked for GQL rendering."), }; diff --git a/query-engine/schema/src/build/input_types/fields/data_input_mapper/update.rs b/query-engine/schema/src/build/input_types/fields/data_input_mapper/update.rs index e6f051b70586..c234d207d0db 100644 --- a/query-engine/schema/src/build/input_types/fields/data_input_mapper/update.rs +++ b/query-engine/schema/src/build/input_types/fields/data_input_mapper/update.rs @@ -39,6 +39,8 @@ impl DataInputFieldMapper for UpdateDataInputFieldMapper { )) } TypeIdentifier::Json => map_scalar_input_type_for_field(ctx, &sf), + // TODO@geometry: Is this the right way ? + TypeIdentifier::Geometry(_) => map_scalar_input_type_for_field(ctx, &sf), TypeIdentifier::DateTime => { InputType::object(update_operations_object_type(ctx, "DateTime", sf.clone(), false)) } diff --git a/query-engine/schema/src/build/input_types/fields/field_filter_types.rs b/query-engine/schema/src/build/input_types/fields/field_filter_types.rs index 84e6faa749ea..54fd16aa1f53 100644 --- a/query-engine/schema/src/build/input_types/fields/field_filter_types.rs +++ b/query-engine/schema/src/build/input_types/fields/field_filter_types.rs @@ -264,6 +264,13 @@ fn full_scalar_filter_type( .chain(inclusion_filters(ctx, mapped_scalar_type.clone(), nullable)) .collect(), + // Inclusion filters are tricky because SQL Server doesn't allow direct equality check between geometries + // so IN ( ... ) filters won't work either. The equality filters are hacked in Quaint, where they are + // converted to .STEquals() expressions + TypeIdentifier::Geometry(_) => geometric_filters(ctx, mapped_scalar_type.clone()) + .chain(equality_filters(mapped_scalar_type.clone(), nullable)) + .collect(), + TypeIdentifier::Unsupported => unreachable!("No unsupported field should reach that path"), }; @@ -462,6 +469,15 @@ fn json_filters(ctx: &'_ QuerySchema) -> impl Iterator> { .into_iter() } +fn geometric_filters<'a>(_ctx: &'a QuerySchema, mapped_type: InputType<'a>) -> impl Iterator> { + let field_types = mapped_type.with_field_ref_input(); + vec![ + input_field(filters::GEO_WITHIN, field_types.clone(), None).optional(), + input_field(filters::GEO_INTERSECTS, field_types.clone(), None).optional(), + ] + .into_iter() +} + fn query_mode_field(ctx: &'_ QuerySchema, nested: bool) -> impl Iterator> { // Limit query mode field to the topmost filter level. // Only build mode field for connectors with insensitive filter support. diff --git a/query-engine/schema/src/build/input_types/mod.rs b/query-engine/schema/src/build/input_types/mod.rs index 14ff37722d6d..e7c8b099f24e 100644 --- a/query-engine/schema/src/build/input_types/mod.rs +++ b/query-engine/schema/src/build/input_types/mod.rs @@ -3,7 +3,7 @@ pub(crate) mod objects; use super::*; use fields::*; -use query_structure::ScalarFieldRef; +use query_structure::{GeometryFormat, ScalarFieldRef}; fn map_scalar_input_type_for_field<'a>(ctx: &'a QuerySchema, field: &ScalarFieldRef) -> InputType<'a> { map_scalar_input_type(ctx, field.type_identifier(), field.is_list()) @@ -19,6 +19,8 @@ fn map_scalar_input_type(ctx: &'_ QuerySchema, typ: TypeIdentifier, list: bool) TypeIdentifier::UUID => InputType::uuid(), TypeIdentifier::DateTime => InputType::date_time(), TypeIdentifier::Json => InputType::json(), + TypeIdentifier::Geometry(GeometryFormat::GeoJSON) => InputType::geojson_geometry(), + TypeIdentifier::Geometry(GeometryFormat::EWKT) => InputType::ewkt_geometry(), TypeIdentifier::Enum(id) => InputType::enum_type(map_schema_enum_type(ctx, id)), TypeIdentifier::Bytes => InputType::bytes(), TypeIdentifier::BigInt => InputType::bigint(), diff --git a/query-engine/schema/src/build/output_types/field.rs b/query-engine/schema/src/build/output_types/field.rs index 29924c9d98c1..00d3a5d793f8 100644 --- a/query-engine/schema/src/build/output_types/field.rs +++ b/query-engine/schema/src/build/output_types/field.rs @@ -1,6 +1,6 @@ use super::*; use input_types::fields::arguments; -use query_structure::{CompositeFieldRef, ScalarFieldRef}; +use query_structure::{CompositeFieldRef, GeometryFormat, ScalarFieldRef}; pub(crate) fn map_output_field(ctx: &'_ QuerySchema, model_field: ModelField) -> OutputField<'_> { let cloned_model_field = model_field.clone(); @@ -34,6 +34,8 @@ pub(crate) fn map_scalar_output_type<'a>(ctx: &'a QuerySchema, typ: &TypeIdentif TypeIdentifier::Boolean => OutputType::boolean(), TypeIdentifier::Enum(e) => OutputType::enum_type(map_schema_enum_type(ctx, *e)), TypeIdentifier::Json => OutputType::json(), + TypeIdentifier::Geometry(GeometryFormat::GeoJSON) => OutputType::geojson_geometry(), + TypeIdentifier::Geometry(GeometryFormat::EWKT) => OutputType::ewkt_geometry(), TypeIdentifier::DateTime => OutputType::date_time(), TypeIdentifier::UUID => OutputType::uuid(), TypeIdentifier::Int => OutputType::int(), diff --git a/query-engine/schema/src/constants.rs b/query-engine/schema/src/constants.rs index 461ce37ef42d..f0c6795fae9b 100644 --- a/query-engine/schema/src/constants.rs +++ b/query-engine/schema/src/constants.rs @@ -106,6 +106,10 @@ pub mod filters { pub const STRING_STARTS_WITH: &str = "string_starts_with"; pub const STRING_ENDS_WITH: &str = "string_ends_with"; pub const JSON_TYPE: &str = "json_type"; + + // geometry filters + pub const GEO_WITHIN: &str = "geoWithin"; + pub const GEO_INTERSECTS: &str = "geoIntersects"; } pub mod aggregations { diff --git a/query-engine/schema/src/input_types.rs b/query-engine/schema/src/input_types.rs index 3a6c0610f600..b133d1622fdc 100644 --- a/query-engine/schema/src/input_types.rs +++ b/query-engine/schema/src/input_types.rs @@ -270,6 +270,14 @@ impl<'a> InputType<'a> { InputType::Scalar(ScalarType::Bytes) } + pub(crate) fn ewkt_geometry() -> InputType<'a> { + InputType::Scalar(ScalarType::Geometry) + } + + pub(crate) fn geojson_geometry() -> InputType<'a> { + InputType::Scalar(ScalarType::GeoJson) + } + pub(crate) fn null() -> InputType<'a> { InputType::Scalar(ScalarType::Null) } diff --git a/query-engine/schema/src/output_types.rs b/query-engine/schema/src/output_types.rs index 32956d01d50b..f42d620f46e6 100644 --- a/query-engine/schema/src/output_types.rs +++ b/query-engine/schema/src/output_types.rs @@ -77,6 +77,14 @@ impl<'a> OutputType<'a> { InnerOutputType::Scalar(ScalarType::Bytes) } + pub(crate) fn ewkt_geometry() -> InnerOutputType<'a> { + InnerOutputType::Scalar(ScalarType::Geometry) + } + + pub(crate) fn geojson_geometry() -> InnerOutputType<'a> { + InnerOutputType::Scalar(ScalarType::GeoJson) + } + /// Attempts to recurse through the type until an object type is found. /// Returns Some(ObjectTypeStrongRef) if ab object type is found, None otherwise. pub fn as_object_type<'b>(&'b self) -> Option<&'b ObjectType<'a>> { diff --git a/query-engine/schema/src/query_schema.rs b/query-engine/schema/src/query_schema.rs index 0324896aea07..d072087e6613 100644 --- a/query-engine/schema/src/query_schema.rs +++ b/query-engine/schema/src/query_schema.rs @@ -313,6 +313,8 @@ pub enum ScalarType { JsonList, UUID, Bytes, + GeoJson, + Geometry, } impl fmt::Display for ScalarType { @@ -330,6 +332,8 @@ impl fmt::Display for ScalarType { ScalarType::UUID => "UUID", ScalarType::JsonList => "Json", ScalarType::Bytes => "Bytes", + ScalarType::GeoJson => "GeoJson", + ScalarType::Geometry => "Geometry", }; f.write_str(typ) diff --git a/schema-engine/connectors/sql-schema-connector/src/flavour/postgres.rs b/schema-engine/connectors/sql-schema-connector/src/flavour/postgres.rs index 4942f0f4eff5..659a9dd984d8 100644 --- a/schema-engine/connectors/sql-schema-connector/src/flavour/postgres.rs +++ b/schema-engine/connectors/sql-schema-connector/src/flavour/postgres.rs @@ -535,6 +535,7 @@ pub(crate) enum Circumstances { IsCockroachDb, CockroachWithPostgresNativeTypes, // FIXME: we should really break and remove this CanPartitionTables, + HasPostGIS, } fn disable_postgres_statement_cache(url: &mut Url) -> ConnectorResult<()> { @@ -624,6 +625,10 @@ where } } + if let Ok(_postgis_version) = connection.query_raw("SELECT PostGIS_version();", &[], ¶ms.url).await { + circumstances |= Circumstances::HasPostGIS; + } + if let Some(true) = schema_exists_result .get(0) .and_then(|row| row.at(0).and_then(|value| value.as_bool())) diff --git a/schema-engine/connectors/sql-schema-connector/src/flavour/postgres/connection.rs b/schema-engine/connectors/sql-schema-connector/src/flavour/postgres/connection.rs index 9db4ed56b859..71caa76d1e26 100644 --- a/schema-engine/connectors/sql-schema-connector/src/flavour/postgres/connection.rs +++ b/schema-engine/connectors/sql-schema-connector/src/flavour/postgres/connection.rs @@ -59,6 +59,10 @@ impl Connection { describer_circumstances |= describer::Circumstances::Cockroach; } + if circumstances.contains(super::Circumstances::HasPostGIS) { + describer_circumstances |= describer::Circumstances::HasPostGIS; + } + if circumstances.contains(super::Circumstances::CockroachWithPostgresNativeTypes) { describer_circumstances |= describer::Circumstances::CockroachWithPostgresNativeTypes; } diff --git a/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite.rs b/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite.rs index 6570682f4d95..2c6ca751c854 100644 --- a/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite.rs +++ b/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite.rs @@ -20,6 +20,14 @@ pub(crate) struct SqliteFlavour { state: State, } +impl SqliteFlavour { + pub(crate) fn has_spatialite(&self) -> bool { + // TODO@geometry: FIXME! how can we set this at instanciation ? + // currently set to false to avoid too many failing tests + false + } +} + impl Default for SqliteFlavour { fn default() -> Self { SqliteFlavour { state: State::Initial } diff --git a/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite/connection.rs b/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite/connection.rs index 959ed6de8632..bf43f1446f2a 100644 --- a/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite/connection.rs +++ b/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite/connection.rs @@ -2,7 +2,7 @@ pub(crate) use quaint::connector::rusqlite; -use quaint::connector::{GetRow, ToColumnNames}; +use quaint::connector::{rusqlite::LoadExtensionGuard, GetRow, ToColumnNames}; use schema_connector::{ConnectorError, ConnectorResult}; use sql_schema_describer::{sqlite as describer, DescriberErrorKind, SqlSchema}; use std::sync::Mutex; @@ -10,15 +10,27 @@ use user_facing_errors::schema_engine::ApplyMigrationError; pub(super) struct Connection(Mutex); +fn load_spatialite(conn: &rusqlite::Connection) { + // TODO@geometry: raise an appropriate error when spatialite cannot be loaded instead + if let Ok(spatialite_path) = std::env::var("SPATIALITE_PATH") { + unsafe { + let _guard = LoadExtensionGuard::new(conn).unwrap(); + conn.load_extension(spatialite_path, None).unwrap(); + } + } +} + impl Connection { pub(super) fn new(params: &super::Params) -> ConnectorResult { - Ok(Connection(Mutex::new( - rusqlite::Connection::open(¶ms.file_path).map_err(convert_error)?, - ))) + let conn = rusqlite::Connection::open(¶ms.file_path).map_err(convert_error)?; + load_spatialite(&conn); + Ok(Connection(Mutex::new(conn))) } pub(super) fn new_in_memory() -> Self { - Connection(Mutex::new(rusqlite::Connection::open_in_memory().unwrap())) + let conn = rusqlite::Connection::open_in_memory().unwrap(); + load_spatialite(&conn); + Connection(Mutex::new(conn)) } pub(super) async fn describe_schema(&mut self) -> ConnectorResult { 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 e0536b70f432..98bd9406acc9 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 @@ -90,6 +90,7 @@ impl<'a> ScalarFieldPair<'a> { sql::ColumnTypeFamily::DateTime => Cow::from("DateTime"), sql::ColumnTypeFamily::Binary => Cow::from("Bytes"), sql::ColumnTypeFamily::Json => Cow::from("Json"), + sql::ColumnTypeFamily::Geometry => Cow::from("Geometry"), sql::ColumnTypeFamily::Uuid => Cow::from("String"), sql::ColumnTypeFamily::Enum(id) => self.context.enum_prisma_name(*id).prisma_name(), sql::ColumnTypeFamily::Unsupported(ref typ) => Cow::from(typ), @@ -107,6 +108,7 @@ impl<'a> ScalarFieldPair<'a> { sql::ColumnTypeFamily::String => Some(psl::parser_database::ScalarType::String), sql::ColumnTypeFamily::DateTime => Some(psl::parser_database::ScalarType::DateTime), sql::ColumnTypeFamily::Json => Some(psl::parser_database::ScalarType::Json), + sql::ColumnTypeFamily::Geometry => Some(psl::parser_database::ScalarType::Geometry), sql::ColumnTypeFamily::Uuid => Some(psl::parser_database::ScalarType::String), sql::ColumnTypeFamily::Binary => Some(psl::parser_database::ScalarType::Bytes), sql::ColumnTypeFamily::Enum(_) => None, diff --git a/schema-engine/connectors/sql-schema-connector/src/lib.rs b/schema-engine/connectors/sql-schema-connector/src/lib.rs index 66924c2b5a9b..b9a41609b421 100644 --- a/schema-engine/connectors/sql-schema-connector/src/lib.rs +++ b/schema-engine/connectors/sql-schema-connector/src/lib.rs @@ -1,6 +1,6 @@ //! The SQL migration connector. -#![deny(rust_2018_idioms, unsafe_code, missing_docs)] +#![deny(rust_2018_idioms, missing_docs)] mod apply_migration; mod database_schema; diff --git a/schema-engine/connectors/sql-schema-connector/src/sql_renderer.rs b/schema-engine/connectors/sql-schema-connector/src/sql_renderer.rs index 74ee2c573ece..7287de59e492 100644 --- a/schema-engine/connectors/sql-schema-connector/src/sql_renderer.rs +++ b/schema-engine/connectors/sql-schema-connector/src/sql_renderer.rs @@ -70,6 +70,11 @@ pub(crate) trait SqlRenderer { /// Render a table creation with the provided table name. fn render_create_table_as(&self, table: TableWalker<'_>, table_name: QuotedWithPrefix<&str>) -> String; + /// Render geometry columns creation (Spatialite only) + fn render_create_geometry_columns(&self, _table: TableWalker<'_>, _table_name: QuotedWithPrefix<&str>) -> String { + unreachable!("unreachable render_create_geometry_columns") + } + fn render_drop_and_recreate_index(&self, _indexes: MigrationPair>) -> Vec { unreachable!("unreachable render_drop_and_recreate_index") } diff --git a/schema-engine/connectors/sql-schema-connector/src/sql_renderer/mssql_renderer.rs b/schema-engine/connectors/sql-schema-connector/src/sql_renderer/mssql_renderer.rs index 540542648ea2..7594e2cc752e 100644 --- a/schema-engine/connectors/sql-schema-connector/src/sql_renderer/mssql_renderer.rs +++ b/schema-engine/connectors/sql-schema-connector/src/sql_renderer/mssql_renderer.rs @@ -514,6 +514,8 @@ fn render_column_type(column: sql::TableColumnWalker<'_>) -> Cow<'static, str> { MsSqlType::VarBinary(len) => format!("VARBINARY{len}", len = format_type_param(*len)).into(), MsSqlType::Image => "IMAGE".into(), MsSqlType::Xml => "XML".into(), + MsSqlType::Geometry => "GEOMETRY".into(), + MsSqlType::Geography => "GEOGRAPHY".into(), MsSqlType::UniqueIdentifier => "UNIQUEIDENTIFIER".into(), } } diff --git a/schema-engine/connectors/sql-schema-connector/src/sql_renderer/mysql_renderer.rs b/schema-engine/connectors/sql-schema-connector/src/sql_renderer/mysql_renderer.rs index 4f96aea6fd69..617f0915665b 100644 --- a/schema-engine/connectors/sql-schema-connector/src/sql_renderer/mysql_renderer.rs +++ b/schema-engine/connectors/sql-schema-connector/src/sql_renderer/mysql_renderer.rs @@ -408,6 +408,13 @@ fn render_column_type(column: TableColumnWalker<'_>) -> Cow<'static, str> { } } + fn render_srid(input: Option) -> String { + match input { + None => "".to_string(), + Some(srid) => format!(" SRID {srid}"), + } + } + fn render_decimal(input: Option<(u32, u32)>) -> String { match input { None => "".to_string(), @@ -449,6 +456,14 @@ fn render_column_type(column: TableColumnWalker<'_>) -> Cow<'static, str> { MySqlType::UnsignedTinyInt => "TINYINT UNSIGNED".into(), MySqlType::UnsignedMediumInt => "MEDIUMINT UNSIGNED".into(), MySqlType::UnsignedBigInt => "BIGINT UNSIGNED".into(), + MySqlType::Geometry(srid) => format!("GEOMETRY{}", render_srid(*srid)).into(), + MySqlType::Point(srid) => format!("POINT{}", render_srid(*srid)).into(), + MySqlType::LineString(srid) => format!("LINESTRING{}", render_srid(*srid)).into(), + MySqlType::Polygon(srid) => format!("POLYGON{}", render_srid(*srid)).into(), + MySqlType::MultiPoint(srid) => format!("MULTIPOINT{}", render_srid(*srid)).into(), + MySqlType::MultiLineString(srid) => format!("MULTILINESTRING{}", render_srid(*srid)).into(), + MySqlType::MultiPolygon(srid) => format!("MULTIPOLYGON{}", render_srid(*srid)).into(), + MySqlType::GeometryCollection(srid) => format!("GEOMETRYCOLLECTION{}", render_srid(*srid)).into(), } } diff --git a/schema-engine/connectors/sql-schema-connector/src/sql_renderer/postgres_renderer.rs b/schema-engine/connectors/sql-schema-connector/src/sql_renderer/postgres_renderer.rs index fdebc14f89b2..cacbcdd79854 100644 --- a/schema-engine/connectors/sql-schema-connector/src/sql_renderer/postgres_renderer.rs +++ b/schema-engine/connectors/sql-schema-connector/src/sql_renderer/postgres_renderer.rs @@ -8,7 +8,7 @@ use crate::{ }, sql_schema_differ::{ColumnChange, ColumnChanges}, }; -use psl::builtin_connectors::{CockroachType, PostgresType}; +use psl::builtin_connectors::{CockroachType, GeometryParams, PostgresType}; use sql_ddl::{ postgres::{self as ddl, PostgresIdentifier}, IndexColumn, SortOrder, @@ -587,6 +587,8 @@ fn render_column_type_postgres(col: TableColumnWalker<'_>) -> Cow<'static, str> PostgresType::Xml => "XML".into(), PostgresType::Json => "JSON".into(), PostgresType::JsonB => "JSONB".into(), + PostgresType::Geometry(geom) => format!("GEOMETRY{}", render_geometry_arg(*geom)).into(), + PostgresType::Geography(geom) => format!("GEOGRAPHY{}", render_geometry_arg(*geom)).into(), }; if t.arity.is_list() { @@ -628,6 +630,8 @@ fn render_column_type_cockroachdb(col: TableColumnWalker<'_>) -> Cow<'static, st CockroachType::VarBit(length) => format!("VARBIT{}", render_optional_args(*length)).into(), CockroachType::Uuid => "UUID".into(), CockroachType::JsonB => "JSONB".into(), + CockroachType::Geometry(geom) => format!("GEOMETRY{}", render_geometry_arg(*geom)).into(), + CockroachType::Geography(geom) => format!("GEOGRAPHY{}", render_geometry_arg(*geom)).into(), }; if t.arity.is_list() { @@ -651,6 +655,14 @@ fn render_decimal_args(input: Option<(u32, u32)>) -> String { } } +fn render_geometry_arg(input: Option) -> String { + match input { + None => "".to_string(), + Some(GeometryParams { ty, srid: 0 }) => format!("({ty})"), + Some(GeometryParams { ty, srid }) => format!("({ty}, {srid})"), + } +} + /// Escape an in-memory string so it becomes a valid string literal with default escaping, i.e. /// replacing `'` characters with `''`. fn escape_string_literal(s: &str) -> Cow<'_, str> { diff --git a/schema-engine/connectors/sql-schema-connector/src/sql_renderer/sqlite_renderer.rs b/schema-engine/connectors/sql-schema-connector/src/sql_renderer/sqlite_renderer.rs index b0e79b515814..9485a3a7b9b0 100644 --- a/schema-engine/connectors/sql-schema-connector/src/sql_renderer/sqlite_renderer.rs +++ b/schema-engine/connectors/sql-schema-connector/src/sql_renderer/sqlite_renderer.rs @@ -6,10 +6,11 @@ use crate::{ }; use indoc::formatdoc; use once_cell::sync::Lazy; +use psl::builtin_connectors::SQLiteType; use regex::Regex; use sql_ddl::sqlite as ddl; use sql_schema_describer::{walkers::*, *}; -use std::borrow::Cow; +use std::{fmt::Write, borrow::Cow}; impl SqlRenderer for SqliteFlavour { fn quote<'a>(&self, name: &'a str) -> Quoted<&'a str> { @@ -141,7 +142,36 @@ impl SqlRenderer for SqliteFlavour { .map(|c| c.map(|c| c.name().into()).collect()); } - create_table.to_string() + let create_geometries = &self.render_create_geometry_columns(table, table_name); + if create_geometries.is_empty() { + create_table.to_string() + } else { + create_table.to_string() + "\n;" + create_geometries + } + } + + fn render_create_geometry_columns(&self, table: TableWalker<'_>, table_name: QuotedWithPrefix<&str>) -> String { + // TODO@geometry: RecoverGeometryColumn doesn't error, it returns 1 on success and 0 on failure + // Is that sufficient to signal failure to the migration script or do we need special handing ? + let table_name = table_name.to_string(); + let table_name = &table_name[1..table_name.len() - 1]; // Because we need it as an unqoted string + table + .columns() + .filter(|c| c.column_type_family().is_geometry()) + .fold(String::new(), |mut result, col| { + let column_name = col.name(); + let SQLiteType::Geometry(geom) = col.column_native_type().unwrap(); + let geom = geom.expect("Couldn't get geometry column type informations"); + writeln!( + result, + "SELECT RecoverGeometryColumn('{table_name}', '{column_name}', {srid}, '{ty}', '{dims}');", + srid = geom.srid, + ty = geom.ty.as_2d(), + dims = geom.ty.dimensions(), + ) + .unwrap(); + result + }) } fn render_drop_enum(&self, _: EnumWalker<'_>) -> Vec { @@ -173,8 +203,12 @@ impl SqlRenderer for SqliteFlavour { stmt.push_str("PRAGMA foreign_keys=off"); }); step.render_statement(&mut |stmt| { - stmt.push_str("DROP TABLE "); - stmt.push_display(&Quoted::sqlite_ident(table_name)); + if self.has_spatialite() { + stmt.push_str(&format!("SELECT DropTable(NULL, '{}')", table_name)); + } else { + stmt.push_str("DROP TABLE "); + stmt.push_display(&Quoted::sqlite_ident(table_name)); + } }); step.render_statement(&mut |stmt| { stmt.push_str("PRAGMA foreign_keys=on"); @@ -197,13 +231,21 @@ impl SqlRenderer for SqliteFlavour { copy_current_table_into_new_table(&mut result, redefine_table, tables, &temporary_table_name); - result.push(format!(r#"DROP TABLE "{}""#, tables.previous.name())); - - result.push(format!( - r#"ALTER TABLE "{old_name}" RENAME TO "{new_name}""#, - old_name = temporary_table_name, - new_name = tables.next.name(), - )); + if self.has_spatialite() { + result.push(format!("SELECT DropTable(NULL, '{}')", tables.previous.name())); + result.push(format!( + "SELECT RenameTable('{old_name}', '{new_name}')", + old_name = temporary_table_name, + new_name = tables.next.name(), + )); + } else { + result.push(format!(r#"DROP TABLE "{}""#, tables.previous.name())); + result.push(format!( + r#"ALTER TABLE "{old_name}" RENAME TO "{new_name}""#, + old_name = temporary_table_name, + new_name = tables.next.name(), + )); + } for index in tables.next.indexes().filter(|idx| !idx.is_primary_key()) { result.push(self.render_create_index(index)); @@ -217,7 +259,11 @@ impl SqlRenderer for SqliteFlavour { } fn render_rename_table(&self, _namespace: Option<&str>, name: &str, new_name: &str) -> String { - format!(r#"ALTER TABLE "{name}" RENAME TO "{new_name}""#) + if self.has_spatialite() { + format!("SELECT RenameTable(NULL, '{name}', '{new_name}')") + } else { + format!(r#"ALTER TABLE "{name}" RENAME TO "{new_name}""#) + } } fn render_drop_view(&self, view: ViewWalker<'_>) -> String { @@ -243,6 +289,8 @@ fn render_column_type(t: &ColumnType) -> &str { ColumnTypeFamily::BigInt => "BIGINT", ColumnTypeFamily::String => "TEXT", ColumnTypeFamily::Binary => "BLOB", + // TODO@geometry: Ideally, render 2D native geometry type instead (not necessary) + ColumnTypeFamily::Geometry => "GEOMETRY", ColumnTypeFamily::Json => unreachable!("ColumnTypeFamily::Json on SQLite"), ColumnTypeFamily::Enum(_) => unreachable!("ColumnTypeFamily::Enum on SQLite"), ColumnTypeFamily::Uuid => unimplemented!("ColumnTypeFamily::Uuid on SQLite"), diff --git a/schema-engine/connectors/sql-schema-connector/src/sql_schema_calculator.rs b/schema-engine/connectors/sql-schema-connector/src/sql_schema_calculator.rs index 10a87b96d5a5..3814e8f0f00f 100644 --- a/schema-engine/connectors/sql-schema-connector/src/sql_schema_calculator.rs +++ b/schema-engine/connectors/sql-schema-connector/src/sql_schema_calculator.rs @@ -461,6 +461,8 @@ fn push_column_for_builtin_scalar_type( ScalarType::Bytes => sql::ColumnTypeFamily::Binary, ScalarType::Decimal => sql::ColumnTypeFamily::Decimal, ScalarType::BigInt => sql::ColumnTypeFamily::BigInt, + ScalarType::Geometry => sql::ColumnTypeFamily::Geometry, + ScalarType::GeoJson => sql::ColumnTypeFamily::Geometry, }; let native_type = field diff --git a/schema-engine/connectors/sql-schema-connector/src/sql_schema_differ/sql_schema_differ_flavour/mssql.rs b/schema-engine/connectors/sql-schema-connector/src/sql_schema_differ/sql_schema_differ_flavour/mssql.rs index 01b89e78d9aa..b183b544c303 100644 --- a/schema-engine/connectors/sql-schema-connector/src/sql_schema_differ/sql_schema_differ_flavour/mssql.rs +++ b/schema-engine/connectors/sql-schema-connector/src/sql_schema_differ/sql_schema_differ_flavour/mssql.rs @@ -123,6 +123,16 @@ fn native_type_change_riskyness(previous: &MsSqlType, next: &MsSqlType) -> Optio use MsSqlTypeParameter::*; let cast = || match previous { + MsSqlType::Geometry => match next { + MsSqlType::Geometry => SafeCast, + _ => NotCastable, + }, + + MsSqlType::Geography => match next { + MsSqlType::Geography => SafeCast, + _ => NotCastable, + }, + // Bit, as in booleans. 1 or 0. MsSqlType::Bit => match next { MsSqlType::TinyInt => SafeCast, diff --git a/schema-engine/connectors/sql-schema-connector/src/sql_schema_differ/sql_schema_differ_flavour/mysql.rs b/schema-engine/connectors/sql-schema-connector/src/sql_schema_differ/sql_schema_differ_flavour/mysql.rs index 4f4dea5c7a45..aa42843dd234 100644 --- a/schema-engine/connectors/sql-schema-connector/src/sql_schema_differ/sql_schema_differ_flavour/mysql.rs +++ b/schema-engine/connectors/sql-schema-connector/src/sql_schema_differ/sql_schema_differ_flavour/mysql.rs @@ -158,6 +158,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option not_castable(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::Binary(size) => match next { MySqlType::Binary(n) if n == size => return None, @@ -196,6 +205,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option risky(), MySqlType::Date | MySqlType::DateTime(_) | MySqlType::Json | MySqlType::Timestamp(_) => not_castable(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::Bit(n) => match next { MySqlType::Bit(m) if n == m => return None, @@ -236,6 +254,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option not_castable(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::Blob => match next { MySqlType::Blob => return None, @@ -271,6 +298,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option not_castable(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::Char(n) => match next { MySqlType::Char(m) if m == n => return None, @@ -312,6 +348,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option risky(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::Date => match next { MySqlType::Date => return None, @@ -335,6 +380,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option not_castable(), + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), + // To string MySqlType::Binary(_) | MySqlType::Bit(_) @@ -386,6 +440,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option not_castable(), + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), + MySqlType::Timestamp(_) | MySqlType::Time(_) | MySqlType::Date => safe(), }, MySqlType::Decimal(n) => match next { @@ -425,6 +488,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option risky(), MySqlType::DateTime(_) | MySqlType::Timestamp(_) | MySqlType::Date => not_castable(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::Double => match next { MySqlType::Double => return None, @@ -469,6 +541,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option safe(), MySqlType::Timestamp(_) | MySqlType::DateTime(_) | MySqlType::Date => not_castable(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::Float => match next { MySqlType::Float => return None, @@ -514,6 +595,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option safe(), MySqlType::Timestamp(_) | MySqlType::DateTime(_) | MySqlType::Date => not_castable(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::Int => match next { MySqlType::Int => return None, @@ -555,6 +645,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option not_castable(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::Json => match next { MySqlType::Json => return None, @@ -594,6 +693,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option not_castable(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::LongBlob => match next { MySqlType::LongBlob => return None, @@ -629,6 +737,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option not_castable(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::LongText => match next { MySqlType::LongText => return None, @@ -668,6 +785,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option risky(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::MediumBlob => match next { MySqlType::MediumBlob => return None, @@ -703,6 +829,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option not_castable(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::MediumInt => match next { MySqlType::MediumInt => return None, @@ -744,6 +879,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option not_castable(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::MediumText => match next { MySqlType::MediumText => return None, @@ -783,6 +927,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option risky(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::SmallInt => match next { @@ -820,6 +973,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option not_castable(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::Text => match next { @@ -860,6 +1022,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option risky(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::Time(n) => match next { @@ -886,6 +1057,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option not_castable(), + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), + // To numeric MySqlType::BigInt | MySqlType::Bit(_) @@ -937,6 +1117,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option not_castable(), + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), + MySqlType::DateTime(_) | MySqlType::Time(_) | MySqlType::Date => safe(), }, @@ -974,6 +1163,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option not_castable(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::TinyInt => match next { @@ -1013,6 +1211,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option not_castable(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::TinyText => match next { @@ -1054,6 +1261,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option risky(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::UnsignedBigInt => match next { @@ -1094,6 +1310,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option not_castable(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::UnsignedInt => match next { @@ -1134,6 +1359,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option not_castable(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::UnsignedMediumInt => match next { MySqlType::UnsignedMediumInt => return None, @@ -1173,6 +1407,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option not_castable(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::UnsignedSmallInt => match next { MySqlType::UnsignedSmallInt => return None, @@ -1211,6 +1454,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option not_castable(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::UnsignedTinyInt => match next { MySqlType::UnsignedTinyInt => return None, @@ -1251,6 +1503,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option not_castable(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::VarBinary(n) => match next { MySqlType::VarBinary(m) if n > m => risky(), @@ -1289,6 +1550,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option not_castable(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::VarChar(n) => match next { MySqlType::VarChar(m) if m == n => return None, @@ -1329,6 +1599,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option risky(), + + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), }, MySqlType::Year => match next { MySqlType::Year => return None, @@ -1362,6 +1641,15 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option risky(), + MySqlType::Geometry(_) + | MySqlType::Point(_) + | MySqlType::LineString(_) + | MySqlType::Polygon(_) + | MySqlType::MultiPoint(_) + | MySqlType::MultiLineString(_) + | MySqlType::MultiPolygon(_) + | MySqlType::GeometryCollection(_) => not_castable(), + MySqlType::Date | MySqlType::DateTime(_) | MySqlType::Time(_) @@ -1369,5 +1657,78 @@ fn native_type_change(types: MigrationPair<&MySqlType>) -> Option not_castable(), // out of range }, + // TODO@geometry: MySQL 8+ can actually cast between spatial types (https://dev.mysql.com/doc/refman/8.0/en/cast-functions.html#cast-spatial-types) + MySqlType::Geometry(_) => match next { + MySqlType::TinyBlob + | MySqlType::Blob + | MySqlType::MediumBlob + | MySqlType::LongBlob + | MySqlType::Binary(_) + | MySqlType::VarBinary(_) => risky(), + _ => not_castable(), + }, + MySqlType::Point(_) => match next { + MySqlType::TinyBlob + | MySqlType::Blob + | MySqlType::MediumBlob + | MySqlType::LongBlob + | MySqlType::Binary(_) + | MySqlType::VarBinary(_) => risky(), + _ => not_castable(), + }, + MySqlType::LineString(_) => match next { + MySqlType::TinyBlob + | MySqlType::Blob + | MySqlType::MediumBlob + | MySqlType::LongBlob + | MySqlType::Binary(_) + | MySqlType::VarBinary(_) => risky(), + _ => not_castable(), + }, + MySqlType::Polygon(_) => match next { + MySqlType::TinyBlob + | MySqlType::Blob + | MySqlType::MediumBlob + | MySqlType::LongBlob + | MySqlType::Binary(_) + | MySqlType::VarBinary(_) => risky(), + _ => not_castable(), + }, + MySqlType::MultiPoint(_) => match next { + MySqlType::TinyBlob + | MySqlType::Blob + | MySqlType::MediumBlob + | MySqlType::LongBlob + | MySqlType::Binary(_) + | MySqlType::VarBinary(_) => risky(), + _ => not_castable(), + }, + MySqlType::MultiLineString(_) => match next { + MySqlType::TinyBlob + | MySqlType::Blob + | MySqlType::MediumBlob + | MySqlType::LongBlob + | MySqlType::Binary(_) + | MySqlType::VarBinary(_) => risky(), + _ => not_castable(), + }, + MySqlType::MultiPolygon(_) => match next { + MySqlType::TinyBlob + | MySqlType::Blob + | MySqlType::MediumBlob + | MySqlType::LongBlob + | MySqlType::Binary(_) + | MySqlType::VarBinary(_) => risky(), + _ => not_castable(), + }, + MySqlType::GeometryCollection(_) => match next { + MySqlType::TinyBlob + | MySqlType::Blob + | MySqlType::MediumBlob + | MySqlType::LongBlob + | MySqlType::Binary(_) + | MySqlType::VarBinary(_) => risky(), + _ => not_castable(), + }, }) } 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 81db61b7daed..1c64176f15b4 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 @@ -661,6 +661,14 @@ fn postgres_native_type_change_riskyness(previous: &PostgresType, next: &Postgre VarChar(_) | Char(_) => RiskyCast, _ => NotCastable, }, + Geometry(_) => match next { + Geography(_) | Text | Json | VarChar(_) | Char(_) => RiskyCast, + _ => NotCastable, + }, + Geography(_) => match next { + Geometry(_) | Text | Json | VarChar(_) | Char(_) => RiskyCast, + _ => NotCastable, + }, }) }; diff --git a/schema-engine/connectors/sql-schema-connector/src/sql_schema_differ/sql_schema_differ_flavour/sqlite.rs b/schema-engine/connectors/sql-schema-connector/src/sql_schema_differ/sql_schema_differ_flavour/sqlite.rs index 515f26ac2937..a964512c63b8 100644 --- a/schema-engine/connectors/sql-schema-connector/src/sql_schema_differ/sql_schema_differ_flavour/sqlite.rs +++ b/schema-engine/connectors/sql-schema-connector/src/sql_schema_differ/sql_schema_differ_flavour/sqlite.rs @@ -3,8 +3,83 @@ use crate::{ flavour::SqliteFlavour, migration_pair::MigrationPair, sql_schema_differ::column::ColumnTypeChange, sql_schema_differ::differ_database::DifferDatabase, }; +use once_cell::sync::Lazy; +use regex::RegexSet; use sql_schema_describer::{walkers::TableColumnWalker, ColumnTypeFamily}; +/// These can be tables or views, depending on the PostGIS version. In both cases, they should be ignored. +static SPATIALITE_TABLES_OR_VIEWS: Lazy = Lazy::new(|| { + RegexSet::new([ + "(?i)^data_licenses$", + "(?i)^elementarygeometries$", + "(?i)^geometry_columns$", + "(?i)^geometry_columns_auth$", + "(?i)^geometry_columns_field_infos$", + "(?i)^geometry_columns_statistics$", + "(?i)^geometry_columns_time$", + "(?i)^geom_cols_ref_sys$", + "(?i)^idx_iso_metadata_geometry$", + "(?i)^idx_iso_metadata_geometry_node$", + "(?i)^idx_iso_metadata_geometry_parent$", + "(?i)^idx_iso_metadata_geometry_rowid$", + "(?i)^iso_metadata$", + "(?i)^iso_metadata_reference$", + "(?i)^iso_metadata_view$", + "(?i)^knn2$", + "(?i)^networks$", + "(?i)^raster_coverages$", + "(?i)^raster_coverages_keyword$", + "(?i)^raster_coverages_ref_sys$", + "(?i)^raster_coverages_srid$", + "(?i)^rl2map_configurations$", + "(?i)^rl2map_configurations_view$", + "(?i)^se_external_graphics$", + "(?i)^se_external_graphics_view$", + "(?i)^se_fonts$", + "(?i)^se_fonts_view$", + "(?i)^se_raster_styled_layers$", + "(?i)^se_raster_styled_layers_view$", + "(?i)^se_raster_styles$", + "(?i)^se_raster_styles_view$", + "(?i)^se_vector_styled_layers$", + "(?i)^se_vector_styled_layers_view$", + "(?i)^se_vector_styles$", + "(?i)^se_vector_styles_view$", + "(?i)^spatialindex$", + "(?i)^spatialite_history$", + "(?i)^spatial_ref_sys$", + "(?i)^spatial_ref_sys_all$", + "(?i)^spatial_ref_sys_aux$", + "(?i)^sql_statements_log$", + "(?i)^stored_procedures$", + "(?i)^stored_variables$", + "(?i)^topologies$", + "(?i)^vector_coverages$", + "(?i)^vector_coverages_keyword$", + "(?i)^vector_coverages_ref_sys$", + "(?i)^vector_coverages_srid$", + "(?i)^vector_layers$", + "(?i)^vector_layers_auth$", + "(?i)^vector_layers_field_infos$", + "(?i)^vector_layers_statistics$", + "(?i)^views_geometry_columns$", + "(?i)^views_geometry_columns_auth$", + "(?i)^views_geometry_columns_field_infos$", + "(?i)^views_geometry_columns_statistics$", + "(?i)^virts_geometry_collection$", + "(?i)^virts_geometry_collectionm$", + "(?i)^virts_geometry_columns$", + "(?i)^virts_geometry_columns_auth$", + "(?i)^virts_geometry_columns_field_infos$", + "(?i)^virts_geometry_columns_statistics$", + "(?i)^wms_getcapabilities$", + "(?i)^wms_getmap$", + "(?i)^wms_ref_sys$", + "(?i)^wms_settings$", + ]) + .unwrap() +}); + impl SqlSchemaDifferFlavour for SqliteFlavour { fn can_rename_foreign_key(&self) -> bool { false @@ -62,4 +137,12 @@ impl SqlSchemaDifferFlavour for SqliteFlavour { fn has_unnamed_foreign_keys(&self) -> bool { true } + + fn table_should_be_ignored(&self, table_name: &str) -> bool { + SPATIALITE_TABLES_OR_VIEWS.is_match(table_name) + } + + fn view_should_be_ignored(&self, view_name: &str) -> bool { + SPATIALITE_TABLES_OR_VIEWS.is_match(view_name) + } } diff --git a/schema-engine/sql-introspection-tests/tests/cockroachdb/gin.rs b/schema-engine/sql-introspection-tests/tests/cockroachdb/gin.rs index 148cdb3761bf..cb2a52f91890 100644 --- a/schema-engine/sql-introspection-tests/tests/cockroachdb/gin.rs +++ b/schema-engine/sql-introspection-tests/tests/cockroachdb/gin.rs @@ -21,8 +21,8 @@ async fn gin_unsupported_type(api: &mut TestApi) -> TestResult { let expected = expect![[r#" model A { - id BigInt @id @default(autoincrement()) - data Unsupported("geometry") + id BigInt @id @default(autoincrement()) + data Geometry @@index([data], type: Gin) } 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 888a6037a41c..225a8b5aac14 100644 --- a/schema-engine/sql-introspection-tests/tests/commenting_out/cockroachdb.rs +++ b/schema-engine/sql-introspection-tests/tests/commenting_out/cockroachdb.rs @@ -85,8 +85,7 @@ async fn unsupported_type_keeps_its_usages_cockroach(api: &mut TestApi) -> TestR t.add_column("id", types::primary()); // Geometry/Geography is the only type that is not supported by Prisma, but is also not // indexable (only inverted-indexable). - t.add_column("broken", types::custom("geometry")); - t.add_column("broken2", types::custom("geography")); + t.add_column("broken", types::custom("interval")); }); }) .await?; @@ -95,17 +94,15 @@ async fn unsupported_type_keeps_its_usages_cockroach(api: &mut TestApi) -> TestR *** WARNING *** These fields are not supported by Prisma Client, because Prisma currently does not support their types: - - Model: "Test", field: "broken", original data type: "geometry" - - Model: "Test", field: "broken2", original data type: "geography" + - Model: "Test", field: "broken", original data type: "interval" "#]]; api.expect_warnings(&expected).await; let dm = expect![[r#" model Test { - id BigInt @id @default(autoincrement()) - broken Unsupported("geometry") - broken2 Unsupported("geography") + id BigInt @id @default(autoincrement()) + broken Unsupported("interval") } "#]]; diff --git a/schema-engine/sql-introspection-tests/tests/native_types/mod.rs b/schema-engine/sql-introspection-tests/tests/native_types/mod.rs index 4199b1659cda..261d27f53628 100644 --- a/schema-engine/sql-introspection-tests/tests/native_types/mod.rs +++ b/schema-engine/sql-introspection-tests/tests/native_types/mod.rs @@ -1,3 +1,4 @@ mod mssql; mod mysql; mod postgres; +mod sqlite; diff --git a/schema-engine/sql-introspection-tests/tests/native_types/mssql.rs b/schema-engine/sql-introspection-tests/tests/native_types/mssql.rs index 17424f7c70bf..93e5c5bf1642 100644 --- a/schema-engine/sql-introspection-tests/tests/native_types/mssql.rs +++ b/schema-engine/sql-introspection-tests/tests/native_types/mssql.rs @@ -34,6 +34,8 @@ const TYPES: &[(&str, &str)] = &[ ("image", "Image"), ("text", "Text"), ("ntext", "NText"), + ("geom", "Geometry"), + ("geog", "Geography"), ]; #[test_connector(tags(Mssql))] @@ -88,6 +90,8 @@ async fn native_type_columns_feature_on(api: &mut TestApi) -> TestResult { image Bytes @db.Image text String @db.Text ntext String @db.NText + geom Geometry + geog Geometry @db.Geography } "#}; diff --git a/schema-engine/sql-introspection-tests/tests/native_types/mysql.rs b/schema-engine/sql-introspection-tests/tests/native_types/mysql.rs index a46878d4b0e0..02017171da49 100644 --- a/schema-engine/sql-introspection-tests/tests/native_types/mysql.rs +++ b/schema-engine/sql-introspection-tests/tests/native_types/mysql.rs @@ -42,6 +42,26 @@ const TYPES: &[(&str, &str)] = &[ ("timestampWithPrecision", "Timestamp(3)"), ("year", "Year"), ("json", "Json"), + ("geom", "Geometry"), + ("point", "Point"), + ("line", "LineString"), + ("polygon", "Polygon"), + ("multipoint", "MultiPoint"), + ("multiline", "MultiLineString"), + ("multipolygon", "MultiPolygon"), + ("geometrycollection", "GeometryCollection"), +]; + +const GEOMETRY_SRID_TYPES: &[(&str, &str)] = &[ + ("id", "BigInt Auto_Increment Primary Key"), + ("geom", "Geometry SRID 4326"), + ("point", "Point SRID 4326"), + ("line", "LineString SRID 4326"), + ("polygon", "Polygon SRID 4326"), + ("multipoint", "MultiPoint SRID 4326"), + ("multiline", "MultiLineString SRID 4326"), + ("multipolygon", "MultiPolygon SRID 4326"), + ("geometrycollection", "GeometryCollection SRID 4326"), ]; // NOTE: The MariaDB expectations broke with 10.11.2 @@ -109,6 +129,56 @@ async fn native_type_columns_feature_on(api: &mut TestApi) -> TestResult { timestampWithPrecision DateTime @db.Timestamp(3) year Int @db.Year json {json} + geom Geometry + point Geometry @db.Point + line Geometry @db.LineString + polygon Geometry @db.Polygon + multipoint Geometry @db.MultiPoint + multiline Geometry @db.MultiLineString + multipolygon Geometry @db.MultiPolygon + geometrycollection Geometry @db.GeometryCollection + }} + "#, + }; + + let result = api.introspect().await?; + + println!("EXPECTATION: \n {types:#}"); + println!("RESULT: \n {result:#}"); + + api.assert_eq_datamodels(&types, &result); + + Ok(()) +} + +#[test_connector(tags(Mysql8))] +async fn native_type_geometry_columns_srid_feature_on(api: &mut TestApi) -> TestResult { + let columns: Vec = GEOMETRY_SRID_TYPES + .iter() + .map(|(name, db_type)| format!("`{name}` {db_type} Not Null")) + .collect(); + + api.barrel() + .execute(move |migration| { + migration.create_table("Spatial", move |t| { + for column in &columns { + t.inject_custom(column); + } + }); + }) + .await?; + + let types = formatdoc! {r#" + model Spatial {{ + id BigInt @id @default(autoincrement()) + geom Geometry @db.Geometry(4326) + point Geometry @db.Point(4326) + line Geometry @db.LineString(4326) + polygon Geometry @db.Polygon(4326) + multipoint Geometry @db.MultiPoint(4326) + multiline Geometry @db.MultiLineString(4326) + multipolygon Geometry @db.MultiPolygon(4326) + geometrycollection Geometry @db.GeometryCollection(4326) }} "#, }; 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 f95c6fcbc890..2ff61e6e3644 100644 --- a/schema-engine/sql-introspection-tests/tests/native_types/postgres.rs +++ b/schema-engine/sql-introspection-tests/tests/native_types/postgres.rs @@ -36,7 +36,145 @@ const TYPES: &[(&str, &str)] = &[ ("inet", "Inet"), ]; -#[test_connector(tags(Postgres), exclude(CockroachDb))] +const GEOMETRY_TYPES: &[(&str, &str)] = &[ + ("geometry", "Geometry"), + ("geometry_geometry", "Geometry(Geometry)"), + ("geometry_geometry_srid", "Geometry(Geometry, 4326)"), + ("geometry_geometry_m", "Geometry(GeometryM)"), + ("geometry_geometry_z", "Geometry(GeometryZ)"), + ("geometry_geometry_zm", "Geometry(GeometryZM)"), + ("geometry_point", "Geometry(Point)"), + ("geometry_point_m", "Geometry(PointM)"), + ("geometry_point_z", "Geometry(PointZ)"), + ("geometry_point_zm", "Geometry(PointZM)"), + ("geometry_linestring", "Geometry(LineString)"), + ("geometry_linestring_m", "Geometry(LineStringM)"), + ("geometry_linestring_z", "Geometry(LineStringZ)"), + ("geometry_linestring_zm", "Geometry(LineStringZM)"), + ("geometry_polygon", "Geometry(Polygon)"), + ("geometry_polygon_m", "Geometry(PolygonM)"), + ("geometry_polygon_z", "Geometry(PolygonZ)"), + ("geometry_polygon_zm", "Geometry(PolygonZM)"), + ("geometry_multipoint", "Geometry(MultiPoint)"), + ("geometry_multipoint_m", "Geometry(MultiPointM)"), + ("geometry_multipoint_z", "Geometry(MultiPointZ)"), + ("geometry_multipoint_zm", "Geometry(MultiPointZM)"), + ("geometry_multilinestring", "Geometry(MultiLineString)"), + ("geometry_multilinestring_m", "Geometry(MultiLineStringM)"), + ("geometry_multilinestring_z", "Geometry(MultiLineStringZ)"), + ("geometry_multilinestring_zm", "Geometry(MultiLineStringZM)"), + ("geometry_multipolygon", "Geometry(MultiPolygon)"), + ("geometry_multipolygon_m", "Geometry(MultiPolygonM)"), + ("geometry_multipolygon_z", "Geometry(MultiPolygonZ)"), + ("geometry_multipolygon_zm", "Geometry(MultiPolygonZM)"), + ("geometry_geometrycollection", "Geometry(GeometryCollection)"), + ("geometry_geometrycollection_m", "Geometry(GeometryCollectionM)"), + ("geometry_geometrycollection_z", "Geometry(GeometryCollectionZ)"), + ("geometry_geometrycollection_zm", "Geometry(GeometryCollectionZM)"), + ("geography", "Geography"), + ("geography_geometry", "Geography(Geometry)"), + ("geography_geometry_srid", "Geography(Geometry, 4326)"), + ("geography_geometry_m", "Geography(GeometryM)"), + ("geography_geometry_z", "Geography(GeometryZ)"), + ("geography_geometry_zm", "Geography(GeometryZM)"), + ("geography_point", "Geography(Point)"), + ("geography_point_m", "Geography(PointM)"), + ("geography_point_z", "Geography(PointZ)"), + ("geography_point_zm", "Geography(PointZM)"), + ("geography_linestring", "Geography(LineString)"), + ("geography_linestring_m", "Geography(LineStringM)"), + ("geography_linestring_z", "Geography(LineStringZ)"), + ("geography_linestring_zm", "Geography(LineStringZM)"), + ("geography_polygon", "Geography(Polygon)"), + ("geography_polygon_m", "Geography(PolygonM)"), + ("geography_polygon_z", "Geography(PolygonZ)"), + ("geography_polygon_zm", "Geography(PolygonZM)"), + ("geography_multipoint", "Geography(MultiPoint)"), + ("geography_multipoint_m", "Geography(MultiPointM)"), + ("geography_multipoint_z", "Geography(MultiPointZ)"), + ("geography_multipoint_zm", "Geography(MultiPointZM)"), + ("geography_multilinestring", "Geography(MultiLineString)"), + ("geography_multilinestring_m", "Geography(MultiLineStringM)"), + ("geography_multilinestring_z", "Geography(MultiLineStringZ)"), + ("geography_multilinestring_zm", "Geography(MultiLineStringZM)"), + ("geography_multipolygon", "Geography(MultiPolygon)"), + ("geography_multipolygon_m", "Geography(MultiPolygonM)"), + ("geography_multipolygon_z", "Geography(MultiPolygonZ)"), + ("geography_multipolygon_zm", "Geography(MultiPolygonZM)"), + ("geography_geometrycollection", "Geography(GeometryCollection)"), + ("geography_geometrycollection_m", "Geography(GeometryCollectionM)"), + ("geography_geometrycollection_z", "Geography(GeometryCollectionZ)"), + ("geography_geometrycollection_zm", "Geography(GeometryCollectionZM)"), +]; + +const GEOMETRY_EXTRA_TYPES: &[(&str, &str)] = &[ + ("geometry_circularstring", "Geometry(CircularString)"), + ("geometry_circularstringm", "Geometry(CircularStringM)"), + ("geometry_circularstringz", "Geometry(CircularStringZ)"), + ("geometry_circularstringzm", "Geometry(CircularStringZM)"), + ("geometry_compoundcurve", "Geometry(CompoundCurve)"), + ("geometry_compoundcurvem", "Geometry(CompoundCurveM)"), + ("geometry_compoundcurvez", "Geometry(CompoundCurveZ)"), + ("geometry_compoundcurvezm", "Geometry(CompoundCurveZM)"), + ("geometry_curvepolygon", "Geometry(CurvePolygon)"), + ("geometry_curvepolygonm", "Geometry(CurvePolygonM)"), + ("geometry_curvepolygonz", "Geometry(CurvePolygonZ)"), + ("geometry_curvepolygonzm", "Geometry(CurvePolygonZM)"), + ("geometry_multicurve", "Geometry(MultiCurve)"), + ("geometry_multicurvem", "Geometry(MultiCurveM)"), + ("geometry_multicurvez", "Geometry(MultiCurveZ)"), + ("geometry_multicurvezm", "Geometry(MultiCurveZM)"), + ("geometry_multisurface", "Geometry(MultiSurface)"), + ("geometry_multisurfacem", "Geometry(MultiSurfaceM)"), + ("geometry_multisurfacez", "Geometry(MultiSurfaceZ)"), + ("geometry_multisurfacezm", "Geometry(MultiSurfaceZM)"), + ("geometry_polyhedralsurface", "Geometry(PolyhedralSurface)"), + ("geometry_polyhedralsurfacem", "Geometry(PolyhedralSurfaceM)"), + ("geometry_polyhedralsurfacez", "Geometry(PolyhedralSurfaceZ)"), + ("geometry_polyhedralsurfacezm", "Geometry(PolyhedralSurfaceZM)"), + ("geometry_triangle", "Geometry(Triangle)"), + ("geometry_trianglem", "Geometry(TriangleM)"), + ("geometry_trianglez", "Geometry(TriangleZ)"), + ("geometry_trianglezm", "Geometry(TriangleZM)"), + ("geometry_tin", "Geometry(Tin)"), + ("geometry_tinm", "Geometry(TinM)"), + ("geometry_tinz", "Geometry(TinZ)"), + ("geometry_tinzm", "Geometry(TinZM)"), + ("geography_circularstring", "Geography(CircularString)"), + ("geography_circularstringm", "Geography(CircularStringM)"), + ("geography_circularstringz", "Geography(CircularStringZ)"), + ("geography_circularstringzm", "Geography(CircularStringZM)"), + ("geography_compoundcurve", "Geography(CompoundCurve)"), + ("geography_compoundcurvem", "Geography(CompoundCurveM)"), + ("geography_compoundcurvez", "Geography(CompoundCurveZ)"), + ("geography_compoundcurvezm", "Geography(CompoundCurveZM)"), + ("geography_curvepolygon", "Geography(CurvePolygon)"), + ("geography_curvepolygonm", "Geography(CurvePolygonM)"), + ("geography_curvepolygonz", "Geography(CurvePolygonZ)"), + ("geography_curvepolygonzm", "Geography(CurvePolygonZM)"), + ("geography_multicurve", "Geography(MultiCurve)"), + ("geography_multicurvem", "Geography(MultiCurveM)"), + ("geography_multicurvez", "Geography(MultiCurveZ)"), + ("geography_multicurvezm", "Geography(MultiCurveZM)"), + ("geography_multisurface", "Geography(MultiSurface)"), + ("geography_multisurfacem", "Geography(MultiSurfaceM)"), + ("geography_multisurfacez", "Geography(MultiSurfaceZ)"), + ("geography_multisurfacezm", "Geography(MultiSurfaceZM)"), + ("geography_polyhedralsurface", "Geography(PolyhedralSurface)"), + ("geography_polyhedralsurfacem", "Geography(PolyhedralSurfaceM)"), + ("geography_polyhedralsurfacez", "Geography(PolyhedralSurfaceZ)"), + ("geography_polyhedralsurfacezm", "Geography(PolyhedralSurfaceZM)"), + ("geography_triangle", "Geography(Triangle)"), + ("geography_trianglem", "Geography(TriangleM)"), + ("geography_trianglez", "Geography(TriangleZ)"), + ("geography_trianglezm", "Geography(TriangleZM)"), + ("geography_tin", "Geography(Tin)"), + ("geography_tinm", "Geography(TinM)"), + ("geography_tinz", "Geography(TinZ)"), + ("geography_tinzm", "Geography(TinZM)"), +]; + +#[test_connector(tags(Postgres), exclude(PostGIS, CockroachDb))] async fn native_type_columns_feature_on(api: &mut TestApi) -> TestResult { let columns: Vec = TYPES .iter() @@ -100,7 +238,238 @@ async fn native_type_columns_feature_on(api: &mut TestApi) -> TestResult { Ok(()) } -#[test_connector(tags(Postgres), exclude(CockroachDb))] +#[test_connector(tags(PostGIS))] +async fn native_type_spatial_columns_feature_on(api: &mut TestApi) -> TestResult { + api.raw_cmd("CREATE EXTENSION IF NOT EXISTS postgis").await; + + let columns: Vec = GEOMETRY_TYPES + .iter() + .map(|(name, db_type)| format!("\"{name}\" {db_type} Not Null")) + .collect(); + + api.barrel() + .execute(move |migration| { + migration.create_table("Spatial", move |t| { + t.inject_custom("id Integer Primary Key"); + for column in &columns { + t.inject_custom(column); + } + }); + }) + .await?; + + let mut types = indoc! {r#" + model Spatial { + id Int @id + geometry Geometry + geometry_geometry Geometry + geometry_geometry_srid Geometry @db.Geometry(Geometry, 4326) + geometry_geometry_m Geometry @db.Geometry(GeometryM) + geometry_geometry_z Geometry @db.Geometry(GeometryZ) + geometry_geometry_zm Geometry @db.Geometry(GeometryZM) + geometry_point Geometry @db.Geometry(Point) + geometry_point_m Geometry @db.Geometry(PointM) + geometry_point_z Geometry @db.Geometry(PointZ) + geometry_point_zm Geometry @db.Geometry(PointZM) + geometry_linestring Geometry @db.Geometry(LineString) + geometry_linestring_m Geometry @db.Geometry(LineStringM) + geometry_linestring_z Geometry @db.Geometry(LineStringZ) + geometry_linestring_zm Geometry @db.Geometry(LineStringZM) + geometry_polygon Geometry @db.Geometry(Polygon) + geometry_polygon_m Geometry @db.Geometry(PolygonM) + geometry_polygon_z Geometry @db.Geometry(PolygonZ) + geometry_polygon_zm Geometry @db.Geometry(PolygonZM) + geometry_multipoint Geometry @db.Geometry(MultiPoint) + geometry_multipoint_m Geometry @db.Geometry(MultiPointM) + geometry_multipoint_z Geometry @db.Geometry(MultiPointZ) + geometry_multipoint_zm Geometry @db.Geometry(MultiPointZM) + geometry_multilinestring Geometry @db.Geometry(MultiLineString) + geometry_multilinestring_m Geometry @db.Geometry(MultiLineStringM) + geometry_multilinestring_z Geometry @db.Geometry(MultiLineStringZ) + geometry_multilinestring_zm Geometry @db.Geometry(MultiLineStringZM) + geometry_multipolygon Geometry @db.Geometry(MultiPolygon) + geometry_multipolygon_m Geometry @db.Geometry(MultiPolygonM) + geometry_multipolygon_z Geometry @db.Geometry(MultiPolygonZ) + geometry_multipolygon_zm Geometry @db.Geometry(MultiPolygonZM) + geometry_geometrycollection Geometry @db.Geometry(GeometryCollection) + geometry_geometrycollection_m Geometry @db.Geometry(GeometryCollectionM) + geometry_geometrycollection_z Geometry @db.Geometry(GeometryCollectionZ) + geometry_geometrycollection_zm Geometry @db.Geometry(GeometryCollectionZM) + geography Geometry @db.Geography(Geometry, 4326) + geography_geometry Geometry @db.Geography(Geometry, 4326) + geography_geometry_srid Geometry @db.Geography(Geometry, 4326) + geography_geometry_m Geometry @db.Geography(GeometryM, 4326) + geography_geometry_z Geometry @db.Geography(GeometryZ, 4326) + geography_geometry_zm Geometry @db.Geography(GeometryZM, 4326) + geography_point Geometry @db.Geography(Point, 4326) + geography_point_m Geometry @db.Geography(PointM, 4326) + geography_point_z Geometry @db.Geography(PointZ, 4326) + geography_point_zm Geometry @db.Geography(PointZM, 4326) + geography_linestring Geometry @db.Geography(LineString, 4326) + geography_linestring_m Geometry @db.Geography(LineStringM, 4326) + geography_linestring_z Geometry @db.Geography(LineStringZ, 4326) + geography_linestring_zm Geometry @db.Geography(LineStringZM, 4326) + geography_polygon Geometry @db.Geography(Polygon, 4326) + geography_polygon_m Geometry @db.Geography(PolygonM, 4326) + geography_polygon_z Geometry @db.Geography(PolygonZ, 4326) + geography_polygon_zm Geometry @db.Geography(PolygonZM, 4326) + geography_multipoint Geometry @db.Geography(MultiPoint, 4326) + geography_multipoint_m Geometry @db.Geography(MultiPointM, 4326) + geography_multipoint_z Geometry @db.Geography(MultiPointZ, 4326) + geography_multipoint_zm Geometry @db.Geography(MultiPointZM, 4326) + geography_multilinestring Geometry @db.Geography(MultiLineString, 4326) + geography_multilinestring_m Geometry @db.Geography(MultiLineStringM, 4326) + geography_multilinestring_z Geometry @db.Geography(MultiLineStringZ, 4326) + geography_multilinestring_zm Geometry @db.Geography(MultiLineStringZM, 4326) + geography_multipolygon Geometry @db.Geography(MultiPolygon, 4326) + geography_multipolygon_m Geometry @db.Geography(MultiPolygonM, 4326) + geography_multipolygon_z Geometry @db.Geography(MultiPolygonZ, 4326) + geography_multipolygon_zm Geometry @db.Geography(MultiPolygonZM, 4326) + geography_geometrycollection Geometry @db.Geography(GeometryCollection, 4326) + geography_geometrycollection_m Geometry @db.Geography(GeometryCollectionM, 4326) + geography_geometrycollection_z Geometry @db.Geography(GeometryCollectionZ, 4326) + geography_geometrycollection_zm Geometry @db.Geography(GeometryCollectionZM, 4326) + } + "#} + .to_string(); + + // TODO@geometry: shouldn't spatial_ref_sys be ignored here ? + if !api.is_cockroach() { + types += indoc!( + r#" + /// This table contains check constraints and requires additional setup for migrations. Visit https://pris.ly/d/check-constraints for more info. + model spatial_ref_sys { + srid Int @id + auth_name String? @db.VarChar(256) + auth_srid Int? + srtext String? @db.VarChar(2048) + proj4text String? @db.VarChar(2048) + } + "# + ); + } + + let result = api.introspect().await?; + + println!("EXPECTATION: \n {types:#}"); + println!("RESULT: \n {result:#}"); + + api.assert_eq_datamodels(&types, &result); + + Ok(()) +} + +#[test_connector(tags(PostGIS), exclude(CockroachDb))] +async fn native_type_extra_spatial_columns_feature_on(api: &mut TestApi) -> TestResult { + api.raw_cmd("CREATE EXTENSION IF NOT EXISTS postgis").await; + + let columns: Vec = GEOMETRY_EXTRA_TYPES + .iter() + .map(|(name, db_type)| format!("\"{name}\" {db_type} Not Null")) + .collect(); + + api.barrel() + .execute(move |migration| { + migration.create_table("Spatial", move |t| { + t.inject_custom("id Integer Primary Key"); + for column in &columns { + t.inject_custom(column); + } + }); + }) + .await?; + + let types = indoc! {r#" + model Spatial { + id Int @id + geometry_circularstring Geometry @db.Geometry(CircularString) + geometry_circularstringm Geometry @db.Geometry(CircularStringM) + geometry_circularstringz Geometry @db.Geometry(CircularStringZ) + geometry_circularstringzm Geometry @db.Geometry(CircularStringZM) + geometry_compoundcurve Geometry @db.Geometry(CompoundCurve) + geometry_compoundcurvem Geometry @db.Geometry(CompoundCurveM) + geometry_compoundcurvez Geometry @db.Geometry(CompoundCurveZ) + geometry_compoundcurvezm Geometry @db.Geometry(CompoundCurveZM) + geometry_curvepolygon Geometry @db.Geometry(CurvePolygon) + geometry_curvepolygonm Geometry @db.Geometry(CurvePolygonM) + geometry_curvepolygonz Geometry @db.Geometry(CurvePolygonZ) + geometry_curvepolygonzm Geometry @db.Geometry(CurvePolygonZM) + geometry_multicurve Geometry @db.Geometry(MultiCurve) + geometry_multicurvem Geometry @db.Geometry(MultiCurveM) + geometry_multicurvez Geometry @db.Geometry(MultiCurveZ) + geometry_multicurvezm Geometry @db.Geometry(MultiCurveZM) + geometry_multisurface Geometry @db.Geometry(MultiSurface) + geometry_multisurfacem Geometry @db.Geometry(MultiSurfaceM) + geometry_multisurfacez Geometry @db.Geometry(MultiSurfaceZ) + geometry_multisurfacezm Geometry @db.Geometry(MultiSurfaceZM) + geometry_polyhedralsurface Geometry @db.Geometry(PolyhedralSurface) + geometry_polyhedralsurfacem Geometry @db.Geometry(PolyhedralSurfaceM) + geometry_polyhedralsurfacez Geometry @db.Geometry(PolyhedralSurfaceZ) + geometry_polyhedralsurfacezm Geometry @db.Geometry(PolyhedralSurfaceZM) + geometry_triangle Geometry @db.Geometry(Triangle) + geometry_trianglem Geometry @db.Geometry(TriangleM) + geometry_trianglez Geometry @db.Geometry(TriangleZ) + geometry_trianglezm Geometry @db.Geometry(TriangleZM) + geometry_tin Geometry @db.Geometry(Tin) + geometry_tinm Geometry @db.Geometry(TinM) + geometry_tinz Geometry @db.Geometry(TinZ) + geometry_tinzm Geometry @db.Geometry(TinZM) + geography_circularstring Geometry @db.Geography(CircularString, 4326) + geography_circularstringm Geometry @db.Geography(CircularStringM, 4326) + geography_circularstringz Geometry @db.Geography(CircularStringZ, 4326) + geography_circularstringzm Geometry @db.Geography(CircularStringZM, 4326) + geography_compoundcurve Geometry @db.Geography(CompoundCurve, 4326) + geography_compoundcurvem Geometry @db.Geography(CompoundCurveM, 4326) + geography_compoundcurvez Geometry @db.Geography(CompoundCurveZ, 4326) + geography_compoundcurvezm Geometry @db.Geography(CompoundCurveZM, 4326) + geography_curvepolygon Geometry @db.Geography(CurvePolygon, 4326) + geography_curvepolygonm Geometry @db.Geography(CurvePolygonM, 4326) + geography_curvepolygonz Geometry @db.Geography(CurvePolygonZ, 4326) + geography_curvepolygonzm Geometry @db.Geography(CurvePolygonZM, 4326) + geography_multicurve Geometry @db.Geography(MultiCurve, 4326) + geography_multicurvem Geometry @db.Geography(MultiCurveM, 4326) + geography_multicurvez Geometry @db.Geography(MultiCurveZ, 4326) + geography_multicurvezm Geometry @db.Geography(MultiCurveZM, 4326) + geography_multisurface Geometry @db.Geography(MultiSurface, 4326) + geography_multisurfacem Geometry @db.Geography(MultiSurfaceM, 4326) + geography_multisurfacez Geometry @db.Geography(MultiSurfaceZ, 4326) + geography_multisurfacezm Geometry @db.Geography(MultiSurfaceZM, 4326) + geography_polyhedralsurface Geometry @db.Geography(PolyhedralSurface, 4326) + geography_polyhedralsurfacem Geometry @db.Geography(PolyhedralSurfaceM, 4326) + geography_polyhedralsurfacez Geometry @db.Geography(PolyhedralSurfaceZ, 4326) + geography_polyhedralsurfacezm Geometry @db.Geography(PolyhedralSurfaceZM, 4326) + geography_triangle Geometry @db.Geography(Triangle, 4326) + geography_trianglem Geometry @db.Geography(TriangleM, 4326) + geography_trianglez Geometry @db.Geography(TriangleZ, 4326) + geography_trianglezm Geometry @db.Geography(TriangleZM, 4326) + geography_tin Geometry @db.Geography(Tin, 4326) + geography_tinm Geometry @db.Geography(TinM, 4326) + geography_tinz Geometry @db.Geography(TinZ, 4326) + geography_tinzm Geometry @db.Geography(TinZM, 4326) + } + + /// This table contains check constraints and requires additional setup for migrations. Visit https://pris.ly/d/check-constraints for more info. + model spatial_ref_sys { + srid Int @id + auth_name String? @db.VarChar(256) + auth_srid Int? + srtext String? @db.VarChar(2048) + proj4text String? @db.VarChar(2048) + } + "#} + .to_string(); + + let result = api.introspect().await?; + + println!("EXPECTATION: \n {types:#}"); + println!("RESULT: \n {result:#}"); + + api.assert_eq_datamodels(&types, &result); + + Ok(()) +} + +#[test_connector(tags(Postgres), exclude(PostGIS, CockroachDb))] async fn native_type_array_columns_feature_on(api: &mut TestApi) -> TestResult { api.barrel() .execute(move |migration| { diff --git a/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs b/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs new file mode 100644 index 000000000000..6226ae2957ea --- /dev/null +++ b/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs @@ -0,0 +1,91 @@ +use indoc::indoc; +use sql_introspection_tests::test_api::*; + +#[test_connector(tags(Spatialite))] +async fn native_spatial_type_columns_feature_on(api: &mut TestApi) -> TestResult { + let setup = indoc! {r#" + SELECT InitSpatialMetaData(); + + CREATE TABLE "User" ( + id INTEGER PRIMARY KEY + ); + + SELECT + AddGeometryColumn('User', 'geometry_xy', 3857, 'GEOMETRY', 'XY', 0), + AddGeometryColumn('User', 'geometry_xyz', 3857, 'GEOMETRY', 'XYZ', 0), + AddGeometryColumn('User', 'geometry_xym', 3857, 'GEOMETRY', 'XYM', 0), + AddGeometryColumn('User', 'geometry_xyzm', 3857, 'GEOMETRY', 'XYZM', 0), + AddGeometryColumn('User', 'point_xy', 3857, 'POINT', 'XY', 0), + AddGeometryColumn('User', 'point_xyz', 3857, 'POINT', 'XYZ', 0), + AddGeometryColumn('User', 'point_xym', 3857, 'POINT', 'XYM', 0), + AddGeometryColumn('User', 'point_xyzm', 3857, 'POINT', 'XYZM', 0), + AddGeometryColumn('User', 'linestring_xy', 3857, 'LINESTRING', 'XY', 0), + AddGeometryColumn('User', 'linestring_xyz', 3857, 'LINESTRING', 'XYZ', 0), + AddGeometryColumn('User', 'linestring_xym', 3857, 'LINESTRING', 'XYM', 0), + AddGeometryColumn('User', 'linestring_xyzm', 3857, 'LINESTRING', 'XYZM', 0), + AddGeometryColumn('User', 'polygon_xy', 3857, 'POLYGON', 'XY', 0), + AddGeometryColumn('User', 'polygon_xyz', 3857, 'POLYGON', 'XYZ', 0), + AddGeometryColumn('User', 'polygon_xym', 3857, 'POLYGON', 'XYM', 0), + AddGeometryColumn('User', 'polygon_xyzm', 3857, 'POLYGON', 'XYZM', 0), + AddGeometryColumn('User', 'multipoint_xy', 3857, 'MULTIPOINT', 'XY', 0), + AddGeometryColumn('User', 'multipoint_xyz', 3857, 'MULTIPOINT', 'XYZ', 0), + AddGeometryColumn('User', 'multipoint_xym', 3857, 'MULTIPOINT', 'XYM', 0), + AddGeometryColumn('User', 'multipoint_xyzm', 3857, 'MULTIPOINT', 'XYZM', 0), + AddGeometryColumn('User', 'multilinestring_xy', 3857, 'MULTILINESTRING', 'XY', 0), + AddGeometryColumn('User', 'multilinestring_xyz', 3857, 'MULTILINESTRING', 'XYZ', 0), + AddGeometryColumn('User', 'multilinestring_xym', 3857, 'MULTILINESTRING', 'XYM', 0), + AddGeometryColumn('User', 'multilinestring_xyzm', 3857, 'MULTILINESTRING', 'XYZM', 0), + AddGeometryColumn('User', 'multipolygon_xy', 3857, 'MULTIPOLYGON', 'XY', 0), + AddGeometryColumn('User', 'multipolygon_xyz', 3857, 'MULTIPOLYGON', 'XYZ', 0), + AddGeometryColumn('User', 'multipolygon_xym', 3857, 'MULTIPOLYGON', 'XYM', 0), + AddGeometryColumn('User', 'multipolygon_xyzm', 3857, 'MULTIPOLYGON', 'XYZM', 0), + AddGeometryColumn('User', 'geometrycollection_xy', 3857, 'GEOMETRYCOLLECTION', 'XY', 0), + AddGeometryColumn('User', 'geometrycollection_xyz', 3857, 'GEOMETRYCOLLECTION', 'XYZ', 0), + AddGeometryColumn('User', 'geometrycollection_xym', 3857, 'GEOMETRYCOLLECTION', 'XYM', 0), + AddGeometryColumn('User', 'geometrycollection_xyzm', 3857, 'GEOMETRYCOLLECTION', 'XYZM', 0); + "#}; + + api.raw_cmd(setup).await; + + let expectation = expect![[r#" + model User { + id Int @id @default(autoincrement()) + geometry_xy Geometry? @db.Geometry(Geometry, 3857) + geometry_xyz Geometry? @db.Geometry(GeometryZ, 3857) + geometry_xym Geometry? @db.Geometry(GeometryM, 3857) + geometry_xyzm Geometry? @db.Geometry(GeometryZM, 3857) + point_xy Geometry? @db.Geometry(Point, 3857) + point_xyz Geometry? @db.Geometry(PointZ, 3857) + point_xym Geometry? @db.Geometry(PointM, 3857) + point_xyzm Geometry? @db.Geometry(PointZM, 3857) + linestring_xy Geometry? @db.Geometry(LineString, 3857) + linestring_xyz Geometry? @db.Geometry(LineStringZ, 3857) + linestring_xym Geometry? @db.Geometry(LineStringM, 3857) + linestring_xyzm Geometry? @db.Geometry(LineStringZM, 3857) + polygon_xy Geometry? @db.Geometry(Polygon, 3857) + polygon_xyz Geometry? @db.Geometry(PolygonZ, 3857) + polygon_xym Geometry? @db.Geometry(PolygonM, 3857) + polygon_xyzm Geometry? @db.Geometry(PolygonZM, 3857) + multipoint_xy Geometry? @db.Geometry(MultiPoint, 3857) + multipoint_xyz Geometry? @db.Geometry(MultiPointZ, 3857) + multipoint_xym Geometry? @db.Geometry(MultiPointM, 3857) + multipoint_xyzm Geometry? @db.Geometry(MultiPointZM, 3857) + multilinestring_xy Geometry? @db.Geometry(MultiLineString, 3857) + multilinestring_xyz Geometry? @db.Geometry(MultiLineStringZ, 3857) + multilinestring_xym Geometry? @db.Geometry(MultiLineStringM, 3857) + multilinestring_xyzm Geometry? @db.Geometry(MultiLineStringZM, 3857) + multipolygon_xy Geometry? @db.Geometry(MultiPolygon, 3857) + multipolygon_xyz Geometry? @db.Geometry(MultiPolygonZ, 3857) + multipolygon_xym Geometry? @db.Geometry(MultiPolygonM, 3857) + multipolygon_xyzm Geometry? @db.Geometry(MultiPolygonZM, 3857) + geometrycollection_xy Geometry? @db.Geometry(GeometryCollection, 3857) + geometrycollection_xyz Geometry? @db.Geometry(GeometryCollectionZ, 3857) + geometrycollection_xym Geometry? @db.Geometry(GeometryCollectionM, 3857) + geometrycollection_xyzm Geometry? @db.Geometry(GeometryCollectionZM, 3857) + } + "#]]; + + expectation.assert_eq(&api.introspect_dml().await?); + + Ok(()) +} diff --git a/schema-engine/sql-introspection-tests/tests/simple/mssql/geometry_should_be_unsupported.sql b/schema-engine/sql-introspection-tests/tests/simple/mssql/geometry_should_be_unsupported.sql deleted file mode 100644 index e51cdb461df1..000000000000 --- a/schema-engine/sql-introspection-tests/tests/simple/mssql/geometry_should_be_unsupported.sql +++ /dev/null @@ -1,24 +0,0 @@ --- tags=mssql - -CREATE TABLE [dbo].[A] ( - id INT IDENTITY, - location GEOGRAPHY, - CONSTRAINT [A_pkey] PRIMARY KEY (id) -); - - -/* -generator js { - provider = "prisma-client-js" -} - -datasource db { - provider = "sqlserver" - url = env("DATABASE_URL") -} - -model A { - id Int @id @default(autoincrement()) - location Unsupported("geography")? -} -*/ diff --git a/schema-engine/sql-migration-tests/tests/migrations/indexes/cockroachdb/gin.rs b/schema-engine/sql-migration-tests/tests/migrations/indexes/cockroachdb/gin.rs index 96a937399dc6..04e6648d8299 100644 --- a/schema-engine/sql-migration-tests/tests/migrations/indexes/cockroachdb/gin.rs +++ b/schema-engine/sql-migration-tests/tests/migrations/indexes/cockroachdb/gin.rs @@ -70,8 +70,8 @@ fn gin_jsonb_ops(api: TestApi) { fn gin_raw_ops(api: TestApi) { let dm = r#" model A { - id Int @id - data Unsupported("geometry")? + id Int @id + data Geometry? @@index([data], type: Gin) } diff --git a/schema-engine/sql-migration-tests/tests/native_types/mssql.rs b/schema-engine/sql-migration-tests/tests/native_types/mssql.rs index 83d988acb176..89e7fd841633 100644 --- a/schema-engine/sql-migration-tests/tests/native_types/mssql.rs +++ b/schema-engine/sql-migration-tests/tests/native_types/mssql.rs @@ -1875,6 +1875,8 @@ static TYPE_MAPS: Lazy> = Lazy::new(|| { maps.insert("Image", "Bytes"); maps.insert("Xml", "String"); maps.insert("UniqueIdentifier", "String"); + maps.insert("Geometry", "Geometry"); + maps.insert("Geography", "Geometry"); maps }); diff --git a/schema-engine/sql-migration-tests/tests/native_types/mysql.rs b/schema-engine/sql-migration-tests/tests/native_types/mysql.rs index b74f3dd6bac4..0a7c6a67c116 100644 --- a/schema-engine/sql-migration-tests/tests/native_types/mysql.rs +++ b/schema-engine/sql-migration-tests/tests/native_types/mysql.rs @@ -579,51 +579,52 @@ const IMPOSSIBLE_CASTS: Cases = &[ ]; fn native_type_name_to_prisma_scalar_type_name(scalar_type: &str) -> &'static str { - /// Map from native type name to prisma scalar type name. - const TYPES_MAP: &[(&str, &str)] = &[ - ("BigInt", "BigInt"), - ("Binary", "Bytes"), - ("Bit", "Bytes"), - ("Blob", "Bytes"), - ("Char", "String"), - ("Date", "DateTime"), - ("DateTime", "DateTime"), - ("Decimal", "Decimal"), - ("Double", "Float"), - ("Float", "Float"), - ("Int", "Int"), - ("Json", "Json"), - ("LongBlob", "Bytes"), - ("LongText", "String"), - ("MediumBlob", "Bytes"), - ("MediumInt", "Int"), - ("MediumText", "String"), - ("SmallInt", "Int"), - ("Text", "String"), - ("Time", "DateTime"), - ("Timestamp", "DateTime"), - ("TinyBlob", "Bytes"), - ("TinyInt", "Int"), - ("TinyText", "String"), - ("UnsignedBigInt", "BigInt"), - ("UnsignedInt", "Int"), - ("UnsignedMediumInt", "Int"), - ("UnsignedSmallInt", "Int"), - ("UnsignedTinyInt", "Int"), - ("VarBinary", "Bytes"), - ("VarChar", "String"), - ("Year", "Int"), - ]; - let scalar_type = scalar_type.trim_end_matches(|ch: char| [' ', ',', '(', ')'].contains(&ch) || ch.is_ascii_digit()); - let idx = TYPES_MAP - .binary_search_by_key(&scalar_type, |(native, _prisma)| native) - .map_err(|_err| format!("Could not find {scalar_type} in TYPES_MAP")) - .unwrap(); - - TYPES_MAP[idx].1 + match scalar_type { + "BigInt" => "BigInt", + "Binary" => "Bytes", + "Bit" => "Bytes", + "Blob" => "Bytes", + "Char" => "String", + "Date" => "DateTime", + "DateTime" => "DateTime", + "Decimal" => "Decimal", + "Double" => "Float", + "Float" => "Float", + "Int" => "Int", + "Json" => "Json", + "LongBlob" => "Bytes", + "LongText" => "String", + "MediumBlob" => "Bytes", + "MediumInt" => "Int", + "MediumText" => "String", + "SmallInt" => "Int", + "Text" => "String", + "Time" => "DateTime", + "Timestamp" => "DateTime", + "TinyBlob" => "Bytes", + "TinyInt" => "Int", + "TinyText" => "String", + "UnsignedBigInt" => "BigInt", + "UnsignedInt" => "Int", + "UnsignedMediumInt" => "Int", + "UnsignedSmallInt" => "Int", + "UnsignedTinyInt" => "Int", + "VarBinary" => "Bytes", + "VarChar" => "String", + "Year" => "Int", + "Geometry" => "Geometry", + "Point" => "Geometry", + "LineString" => "Geometry", + "Polygon" => "Geometry", + "MultiPoint" => "Geometry", + "MultiLineString" => "Geometry", + "MultiPolygon" => "Geometry", + "GeometryCollection" => "Geometry", + _ => panic!("Could not find {} in TYPES_MAP", scalar_type), + } } fn colnames_for_cases(cases: Cases) -> Vec { diff --git a/schema-engine/sql-schema-describer/src/lib.rs b/schema-engine/sql-schema-describer/src/lib.rs index c5ae677f0e3b..41e36572369c 100644 --- a/schema-engine/sql-schema-describer/src/lib.rs +++ b/schema-engine/sql-schema-describer/src/lib.rs @@ -652,6 +652,8 @@ pub enum ColumnTypeFamily { Binary, /// JSON types. Json, + /// Geometry types. + Geometry, /// UUID types. Uuid, ///Enum @@ -696,6 +698,10 @@ impl ColumnTypeFamily { matches!(self, ColumnTypeFamily::String) } + pub fn is_geometry(&self) -> bool { + matches!(self, ColumnTypeFamily::Geometry) + } + pub fn is_unsupported(&self) -> bool { matches!(self, ColumnTypeFamily::Unsupported(_)) } diff --git a/schema-engine/sql-schema-describer/src/mssql.rs b/schema-engine/sql-schema-describer/src/mssql.rs index 6de97510943d..2727618c3919 100644 --- a/schema-engine/sql-schema-describer/src/mssql.rs +++ b/schema-engine/sql-schema-describer/src/mssql.rs @@ -377,6 +377,7 @@ impl<'a> SqlSchemaDescriber<'a> { }, ColumnTypeFamily::Binary => DefaultValue::db_generated(default_string), ColumnTypeFamily::Json => DefaultValue::db_generated(default_string), + ColumnTypeFamily::Geometry => DefaultValue::db_generated(default_string), ColumnTypeFamily::Uuid => DefaultValue::db_generated(default_string), ColumnTypeFamily::Unsupported(_) => DefaultValue::db_generated(default_string), ColumnTypeFamily::Enum(_) => unreachable!("No enums in MSSQL"), @@ -865,6 +866,8 @@ impl<'a> SqlSchemaDescriber<'a> { "varbinary" => (Binary, Some(MsSqlType::VarBinary(type_parameter))), "image" => (Binary, Some(MsSqlType::Image)), "xml" => (String, Some(MsSqlType::Xml)), + "geometry" => (Geometry, Some(MsSqlType::Geometry)), + "geography" => (Geometry, Some(MsSqlType::Geography)), "uniqueidentifier" => (Uuid, Some(MsSqlType::UniqueIdentifier)), _ => unsupported_type(), }; diff --git a/schema-engine/sql-schema-describer/src/mysql.rs b/schema-engine/sql-schema-describer/src/mysql.rs index 0d5fd98140dd..3eb54d0e42ad 100644 --- a/schema-engine/sql-schema-describer/src/mysql.rs +++ b/schema-engine/sql-schema-describer/src/mysql.rs @@ -89,7 +89,8 @@ impl super::SqlSchemaDescriberBackend for SqlSchemaDescriber<'_> { self.get_constraints(&table_names, &mut sql_schema).await?; - Self::get_all_columns(&table_names, self.conn, schema, &mut sql_schema, &flavour).await?; + self.get_all_columns(&table_names, schema, &mut sql_schema, &flavour) + .await?; push_foreign_keys(schema, &table_names, &mut sql_schema, self.conn).await?; push_indexes(&table_names, schema, &mut sql_schema, self.conn).await?; @@ -358,8 +359,8 @@ impl<'a> SqlSchemaDescriber<'a> { } async fn get_all_columns( + &self, table_ids: &IndexMap, - conn: &dyn Queryable, schema_name: &str, sql_schema: &mut SqlSchema, flavour: &Flavour, @@ -367,7 +368,30 @@ impl<'a> SqlSchemaDescriber<'a> { // We alias all the columns because MySQL column names are case-insensitive in queries, but the // information schema column names became upper-case in MySQL 8, causing the code fetching // the result values by column name below to fail. - let sql = " + let sql_geometry_srid_column = if self.supports_srid_constraints() { + "geom.srs_id" + } else { + "NULL" + }; + + let sql_geometry_information_table = if matches!(flavour, Flavour::MariaDb) { + " + LEFT JOIN information_schema.geometry_columns geom + ON table_schema = geom.g_table_schema + AND table_name = geom.g_table_name + AND column_name = geom.g_geometry_column + " + } else if self.supports_srid_constraints() { + " + LEFT JOIN information_schema.st_geometry_columns geom + USING (table_schema, table_name, column_name) + " + } else { + "" + }; + + let sql = format!( + " SELECT column_name column_name, data_type data_type, @@ -375,20 +399,23 @@ impl<'a> SqlSchemaDescriber<'a> { character_maximum_length character_maximum_length, numeric_precision numeric_precision, numeric_scale numeric_scale, + {sql_geometry_srid_column} geometry_srid, datetime_precision datetime_precision, column_default column_default, is_nullable is_nullable, extra extra, table_name table_name, - IF(column_comment = '', NULL, column_comment) AS column_comment + NULLIF(column_comment, '') AS column_comment FROM information_schema.columns + {sql_geometry_information_table} WHERE table_schema = ? ORDER BY ordinal_position - "; + " + ); let mut table_defaults = Vec::new(); let mut view_defaults = Vec::new(); - let rows = conn.query_raw(sql, &[schema_name.into()]).await?; + let rows = self.conn.query_raw(&sql, &[schema_name.into()]).await?; for col in rows { trace!("Got column: {col:?}"); @@ -424,6 +451,7 @@ impl<'a> SqlSchemaDescriber<'a> { let time_precision = col.get_u32("datetime_precision"); let numeric_precision = col.get_u32("numeric_precision"); let numeric_scale = col.get_u32("numeric_scale"); + let geometry_srid = col.get_u32("geometry_srid"); let precision = Precision { character_maximum_length, @@ -436,9 +464,9 @@ impl<'a> SqlSchemaDescriber<'a> { let tpe = Self::get_column_type( (&table_name, &name), - &data_type, - &full_data_type, + (&data_type, &full_data_type), precision, + geometry_srid, arity, default_value, sql_schema, @@ -513,6 +541,10 @@ impl<'a> SqlSchemaDescriber<'a> { true => Self::dbgenerated_expression(&default_string), false => DefaultValue::db_generated(default_string), }, + ColumnTypeFamily::Geometry => match default_expression { + true => Self::dbgenerated_expression(&default_string), + false => DefaultValue::db_generated(default_string), + }, ColumnTypeFamily::Uuid => match default_expression { true => Self::dbgenerated_expression(&default_string), false => DefaultValue::db_generated(default_string), @@ -603,9 +635,9 @@ impl<'a> SqlSchemaDescriber<'a> { fn get_column_type( (table, column_name): (&str, &str), - data_type: &str, - full_data_type: &str, + (data_type, full_data_type): (&str, &str), precision: Precision, + geometry_srid: Option, arity: ColumnArity, default: Option<&Value<'_>>, sql_schema: &mut SqlSchema, @@ -711,14 +743,20 @@ impl<'a> SqlSchemaDescriber<'a> { "mediumblob" => (ColumnTypeFamily::Binary, Some(MySqlType::MediumBlob)), "longblob" => (ColumnTypeFamily::Binary, Some(MySqlType::LongBlob)), //spatial - "geometry" => (ColumnTypeFamily::Unsupported(full_data_type.into()), None), - "point" => (ColumnTypeFamily::Unsupported(full_data_type.into()), None), - "linestring" => (ColumnTypeFamily::Unsupported(full_data_type.into()), None), - "polygon" => (ColumnTypeFamily::Unsupported(full_data_type.into()), None), - "multipoint" => (ColumnTypeFamily::Unsupported(full_data_type.into()), None), - "multilinestring" => (ColumnTypeFamily::Unsupported(full_data_type.into()), None), - "multipolygon" => (ColumnTypeFamily::Unsupported(full_data_type.into()), None), - "geometrycollection" => (ColumnTypeFamily::Unsupported(full_data_type.into()), None), + "geometry" => (ColumnTypeFamily::Geometry, Some(MySqlType::Geometry(geometry_srid))), + "point" => (ColumnTypeFamily::Geometry, Some(MySqlType::Point(geometry_srid))), + "linestring" => (ColumnTypeFamily::Geometry, Some(MySqlType::LineString(geometry_srid))), + "polygon" => (ColumnTypeFamily::Geometry, Some(MySqlType::Polygon(geometry_srid))), + "multipoint" => (ColumnTypeFamily::Geometry, Some(MySqlType::MultiPoint(geometry_srid))), + "multilinestring" => ( + ColumnTypeFamily::Geometry, + Some(MySqlType::MultiLineString(geometry_srid)), + ), + "multipolygon" => (ColumnTypeFamily::Geometry, Some(MySqlType::MultiPolygon(geometry_srid))), + "geometrycollection" | "geomcollection" => ( + ColumnTypeFamily::Geometry, + Some(MySqlType::GeometryCollection(geometry_srid)), + ), _ => (ColumnTypeFamily::Unsupported(full_data_type.into()), None), }; @@ -815,6 +853,14 @@ impl<'a> SqlSchemaDescriber<'a> { .circumstances .intersects(Circumstances::MySql56 | Circumstances::MySql57 | Circumstances::MariaDb) } + + /// Tests whether the current database supports geometry SRID constraints + fn supports_srid_constraints(&self) -> bool { + // Only MySQL 8 and above supports geometry SRIDs constraints + !self + .circumstances + .intersects(Circumstances::MySql56 | Circumstances::MySql57 | Circumstances::MariaDb) + } } async fn push_foreign_keys( diff --git a/schema-engine/sql-schema-describer/src/postgres.rs b/schema-engine/sql-schema-describer/src/postgres.rs index 211cf8da489a..8283acb79b22 100644 --- a/schema-engine/sql-schema-describer/src/postgres.rs +++ b/schema-engine/sql-schema-describer/src/postgres.rs @@ -13,7 +13,7 @@ use enumflags2::BitFlags; use indexmap::IndexMap; use indoc::indoc; use psl::{ - builtin_connectors::{CockroachType, PostgresType}, + builtin_connectors::{CockroachType, GeometryParams, GeometryType, PostgresType}, datamodel_connector::NativeTypeInstance, }; use quaint::{connector::ResultRow, prelude::Queryable, Value}; @@ -23,6 +23,7 @@ use std::{ collections::{BTreeMap, HashMap}, convert::TryInto, iter::Peekable, + str::FromStr, }; use tracing::trace; @@ -109,6 +110,7 @@ pub enum Circumstances { Cockroach, CockroachWithPostgresNativeTypes, // TODO: this is a temporary workaround CanPartitionTables, + HasPostGIS, } pub struct SqlSchemaDescriber<'a> { @@ -904,9 +906,9 @@ impl<'a> SqlSchemaDescriber<'a> { .circumstances .contains(Circumstances::CockroachWithPostgresNativeTypes) { - get_column_type_cockroachdb(&col, sql_schema) + get_column_type_cockroachdb(&col, sql_schema, &self.circumstances) } else { - get_column_type_postgresql(&col, sql_schema) + get_column_type_postgresql(&col, sql_schema, &self.circumstances) }; let default = col @@ -974,9 +976,29 @@ impl<'a> SqlSchemaDescriber<'a> { Ok(()) } + fn get_geometry_info(col: &str) -> Option { + static GEOM_REGEX: Lazy = + Lazy::new(|| Regex::new(r"^(?Pgeometry|geography)(\((?P.+?)(,(?P\d+))?\))?$").unwrap()); + GEOM_REGEX.captures(col).and_then(|capture| { + let is_geography = capture.name("class").map(|c| c.as_str() == "geography").unwrap(); + let geom_type = capture + .name("type") + .map(|t| GeometryType::from_str(t.as_str())) + .unwrap_or(Ok(GeometryType::default())); + let srid = capture + .name("srid") + .map(|v| v.as_str().parse::()) + .unwrap_or(Ok(if is_geography { 4326 } else { 0 })); + match (geom_type, srid) { + (Ok(ty), Ok(srid)) => Some(GeometryParams { ty, srid }), + _ => None, + } + }) + } + fn get_precision(col: &ResultRow) -> Precision { - let (character_maximum_length, numeric_precision, numeric_scale, time_precision) = - if matches!(col.get_expect_string("data_type").as_str(), "ARRAY") { + match col.get_expect_string("data_type").as_str() { + "ARRAY" => { fn get_single(formatted_type: &str) -> Option { static SINGLE_REGEX: Lazy = Lazy::new(|| Regex::new(r".*\(([0-9]*)\).*\[\]$").unwrap()); @@ -1003,34 +1025,32 @@ impl<'a> SqlSchemaDescriber<'a> { let formatted_type = col.get_expect_string("formatted_type"); let fdt = col.get_expect_string("full_data_type"); - let char_max_length = match fdt.as_str() { + let character_maximum_length = match fdt.as_str() { "_bpchar" | "_varchar" | "_bit" | "_varbit" => get_single(&formatted_type), _ => None, }; - let (num_precision, num_scale) = match fdt.as_str() { + let (numeric_precision, numeric_scale) = match fdt.as_str() { "_numeric" => get_dual(&formatted_type), _ => (None, None), }; - let time = match fdt.as_str() { + let time_precision = match fdt.as_str() { "_timestamptz" | "_timestamp" | "_timetz" | "_time" | "_interval" => get_single(&formatted_type), _ => None, }; - (char_max_length, num_precision, num_scale, time) - } else { - ( - col.get_u32("character_maximum_length"), - col.get_u32("numeric_precision"), - col.get_u32("numeric_scale"), - col.get_u32("datetime_precision"), - ) - }; - - Precision { - character_maximum_length, - numeric_precision, - numeric_scale, - time_precision, + Precision { + character_maximum_length, + numeric_precision, + numeric_scale, + time_precision, + } + } + _ => Precision { + character_maximum_length: col.get_u32("character_maximum_length"), + numeric_precision: col.get_u32("numeric_precision"), + numeric_scale: col.get_u32("numeric_scale"), + time_precision: col.get_u32("datetime_precision"), + }, } } @@ -1535,10 +1555,15 @@ fn index_from_row( } } -fn get_column_type_postgresql(row: &ResultRow, schema: &SqlSchema) -> ColumnType { +fn get_column_type_postgresql( + row: &ResultRow, + schema: &SqlSchema, + circumstances: &BitFlags, +) -> ColumnType { use ColumnTypeFamily::*; let data_type = row.get_expect_string("data_type"); let full_data_type = row.get_expect_string("full_data_type"); + let formatted_type = row.get_expect_string("formatted_type"); let is_required = match row.get_expect_string("is_nullable").to_lowercase().as_ref() { "no" => true, "yes" => false, @@ -1551,6 +1576,10 @@ fn get_column_type_postgresql(row: &ResultRow, schema: &SqlSchema) -> ColumnType false => ColumnArity::Nullable, }; + let geometry = match circumstances.contains(Circumstances::HasPostGIS) { + true => SqlSchemaDescriber::get_geometry_info(&formatted_type), + false => None, + }; let precision = SqlSchemaDescriber::get_precision(row); let unsupported_type = || (Unsupported(full_data_type.clone()), None); let enum_id: Option<_> = match data_type.as_str() { @@ -1610,6 +1639,13 @@ fn get_column_type_postgresql(row: &ResultRow, schema: &SqlSchema) -> ColumnType "tsvector" | "_tsvector" => unsupported_type(), "txid_snapshot" | "_txid_snapshot" => unsupported_type(), "inet" | "_inet" => (String, Some(PostgresType::Inet)), + //postgis + "geometry" => geometry + .map(|_| (Geometry, Some(PostgresType::Geometry(geometry)))) + .unwrap_or_else(unsupported_type), + "geography" => geometry + .map(|_| (Geometry, Some(PostgresType::Geography(geometry)))) + .unwrap_or_else(unsupported_type), //geometric "box" | "_box" => unsupported_type(), "circle" | "_circle" => unsupported_type(), @@ -1629,7 +1665,11 @@ fn get_column_type_postgresql(row: &ResultRow, schema: &SqlSchema) -> ColumnType } // Separate from get_column_type_postgresql because of native types. -fn get_column_type_cockroachdb(row: &ResultRow, schema: &SqlSchema) -> ColumnType { +fn get_column_type_cockroachdb( + row: &ResultRow, + schema: &SqlSchema, + circumstances: &BitFlags, +) -> ColumnType { use ColumnTypeFamily::*; let data_type = row.get_expect_string("data_type"); let full_data_type = row.get_expect_string("full_data_type"); @@ -1645,6 +1685,10 @@ fn get_column_type_cockroachdb(row: &ResultRow, schema: &SqlSchema) -> ColumnTyp false => ColumnArity::Nullable, }; + let geometry_type = match circumstances.contains(Circumstances::HasPostGIS) { + true => SqlSchemaDescriber::get_geometry_info(&data_type), + false => None, + }; let precision = SqlSchemaDescriber::get_precision(row); let unsupported_type = || (Unsupported(full_data_type.clone()), None); let enum_id: Option<_> = match data_type.as_str() { @@ -1699,6 +1743,13 @@ fn get_column_type_cockroachdb(row: &ResultRow, schema: &SqlSchema) -> ColumnTyp "tsvector" | "_tsvector" => unsupported_type(), "txid_snapshot" | "_txid_snapshot" => unsupported_type(), "inet" | "_inet" => (String, Some(CockroachType::Inet)), + //postgis + "geometry" => geometry_type + .map(|_| (Geometry, Some(CockroachType::Geometry(geometry_type)))) + .unwrap_or_else(unsupported_type), + "geography" => geometry_type + .map(|_| (Geometry, Some(CockroachType::Geography(geometry_type)))) + .unwrap_or_else(unsupported_type), //geometric "box" | "_box" => unsupported_type(), "circle" | "_circle" => unsupported_type(), diff --git a/schema-engine/sql-schema-describer/src/postgres/default.rs b/schema-engine/sql-schema-describer/src/postgres/default.rs index 593368d27e66..897ee2df8f6d 100644 --- a/schema-engine/sql-schema-describer/src/postgres/default.rs +++ b/schema-engine/sql-schema-describer/src/postgres/default.rs @@ -94,7 +94,8 @@ pub(super) fn get_default_value(default_string: &str, tpe: &ColumnType) -> Optio fn parser_for_family(family: &ColumnTypeFamily) -> &'static dyn Fn(&mut Parser<'_>) -> Option { match family { - ColumnTypeFamily::String | ColumnTypeFamily::Json => &parse_string_default, + // TODO@geometry: Is this safe ? + ColumnTypeFamily::String | ColumnTypeFamily::Json | ColumnTypeFamily::Geometry => &parse_string_default, ColumnTypeFamily::Int | ColumnTypeFamily::BigInt => &parse_int_default, ColumnTypeFamily::Enum(_) => &parse_enum_default, ColumnTypeFamily::Float | ColumnTypeFamily::Decimal => &parse_float_default, diff --git a/schema-engine/sql-schema-describer/src/postgres/default/c_style_scalar_lists.rs b/schema-engine/sql-schema-describer/src/postgres/default/c_style_scalar_lists.rs index d9e4b9a55e63..3d0561557eb1 100644 --- a/schema-engine/sql-schema-describer/src/postgres/default/c_style_scalar_lists.rs +++ b/schema-engine/sql-schema-describer/src/postgres/default/c_style_scalar_lists.rs @@ -86,6 +86,7 @@ fn parse_literal(s: &str, tpe: &ColumnType) -> Option { ColumnTypeFamily::DateTime | ColumnTypeFamily::Binary | ColumnTypeFamily::Uuid + | ColumnTypeFamily::Geometry | ColumnTypeFamily::Unsupported(_) => None, } } diff --git a/schema-engine/sql-schema-describer/src/sqlite.rs b/schema-engine/sql-schema-describer/src/sqlite.rs index 1f28958605a2..0d23b748c22e 100644 --- a/schema-engine/sql-schema-describer/src/sqlite.rs +++ b/schema-engine/sql-schema-describer/src/sqlite.rs @@ -7,12 +7,24 @@ use crate::{ }; use either::Either; use indexmap::IndexMap; +use psl::{ + builtin_connectors::{GeometryParams, GeometryType, SQLiteType}, + datamodel_connector::NativeTypeInstance, +}; use quaint::{ ast::{Value, ValueType}, connector::{GetRow, ToColumnNames}, prelude::ResultRow, }; -use std::{any::type_name, borrow::Cow, collections::BTreeMap, convert::TryInto, fmt::Debug, path::Path}; +use regex::RegexSet; +use std::{ + any::type_name, + borrow::Cow, + collections::{BTreeMap, HashMap}, + convert::TryInto, + fmt::Debug, + path::Path, +}; use tracing::trace; #[async_trait::async_trait] @@ -107,8 +119,9 @@ impl<'a> SqlSchemaDescriber<'a> { .filter_map(|(name, id)| id.left().map(|id| (name.as_str(), id))) .collect(); + let geometry_columns = get_geometry_columns(self.conn).await; for (container_name, container_id) in &container_ids { - push_columns(container_name, *container_id, &mut schema, self.conn).await?; + push_columns(container_name, *container_id, &geometry_columns, &mut schema, self.conn).await?; if let Either::Left(table_id) = container_id { push_indexes(container_name, *table_id, &mut schema, self.conn).await?; @@ -321,9 +334,47 @@ impl<'a> SqlSchemaDescriber<'a> { } } +async fn get_geometry_columns(conn: &(dyn Connection + Send + Sync)) -> HashMap<(String, String), (GeometryType, i32)> { + let sql = r#" + SELECT + f_table_name, + f_geometry_column, + geometry_type, + srid + FROM + geometry_columns + "#; + let result_set = conn.query_raw(sql, &[]).await; + if result_set.is_err() { + return HashMap::new(); + } + result_set + .unwrap() + .into_iter() + .map(|row| { + ( + ( + row.get_expect_string("f_table_name"), + row.get_expect_string("f_geometry_column"), + ), + ( + // Unwrapping is safe since Spatialite validates the geometry type + u32::try_from(row.get_expect_i64("geometry_type")) + .unwrap() + .try_into() + .unwrap(), + // Unwrapping is safe since Spatialite validates the SRID against the EPSG database + row.get_expect_i64("srid").try_into().unwrap(), + ), + ) + }) + .collect() +} + async fn push_columns( table_name: &str, container_id: Either, + geometry_columns: &HashMap<(String, String), (GeometryType, i32)>, schema: &mut SqlSchema, conn: &(dyn Connection + Send + Sync), ) -> DescriberResult<()> { @@ -340,7 +391,22 @@ async fn push_columns( ColumnArity::Nullable }; - let tpe = get_column_type(row.get_expect_string("type"), arity); + let column_name = row.get_expect_string("name"); + let column_type = row.get_expect_string("type"); + let geometry_info = geometry_columns.get(&(table_name.to_lowercase(), column_name.to_lowercase())); + let tpe = if let Some((ty, srid)) = geometry_info { + ColumnType { + full_data_type: column_type, + family: ColumnTypeFamily::Geometry, + arity, + native_type: Some(NativeTypeInstance::new(SQLiteType::Geometry(Some(GeometryParams { + ty: *ty, + srid: *srid, + })))), + } + } else { + get_column_type(column_type, arity) + }; let default = match row.get("dflt_value") { None => None, @@ -388,6 +454,7 @@ async fn push_columns( } _ => DefaultValue::db_generated(default_string), }, + ColumnTypeFamily::Geometry => DefaultValue::db_generated(default_string), ColumnTypeFamily::Binary => DefaultValue::db_generated(default_string), ColumnTypeFamily::Json => DefaultValue::db_generated(default_string), ColumnTypeFamily::Uuid => DefaultValue::db_generated(default_string), @@ -608,6 +675,7 @@ fn is_system_table(table_name: &str) -> bool { SQLITE_SYSTEM_TABLES .iter() .any(|system_table| table_name == *system_table) + || SPATIALITE_SYSTEM_TABLES.is_match(table_name) } /// See https://www.sqlite.org/fileformat2.html @@ -618,3 +686,76 @@ const SQLITE_SYSTEM_TABLES: &[&str] = &[ "sqlite_stat3", "sqlite_stat4", ]; + +/// These can be tables or views, depending on the Spatialite version. In both cases, they should be ignored. +static SPATIALITE_SYSTEM_TABLES: Lazy = Lazy::new(|| { + RegexSet::new([ + "(?i)^data_licenses$", + "(?i)^elementarygeometries$", + "(?i)^geometry_columns$", + "(?i)^geometry_columns_auth$", + "(?i)^geometry_columns_field_infos$", + "(?i)^geometry_columns_statistics$", + "(?i)^geometry_columns_time$", + "(?i)^geom_cols_ref_sys$", + "(?i)^idx_iso_metadata_geometry$", + "(?i)^idx_iso_metadata_geometry_node$", + "(?i)^idx_iso_metadata_geometry_parent$", + "(?i)^idx_iso_metadata_geometry_rowid$", + "(?i)^iso_metadata$", + "(?i)^iso_metadata_reference$", + "(?i)^iso_metadata_view$", + "(?i)^knn2$", + "(?i)^networks$", + "(?i)^raster_coverages$", + "(?i)^raster_coverages_keyword$", + "(?i)^raster_coverages_ref_sys$", + "(?i)^raster_coverages_srid$", + "(?i)^rl2map_configurations$", + "(?i)^rl2map_configurations_view$", + "(?i)^se_external_graphics$", + "(?i)^se_external_graphics_view$", + "(?i)^se_fonts$", + "(?i)^se_fonts_view$", + "(?i)^se_raster_styled_layers$", + "(?i)^se_raster_styled_layers_view$", + "(?i)^se_raster_styles$", + "(?i)^se_raster_styles_view$", + "(?i)^se_vector_styled_layers$", + "(?i)^se_vector_styled_layers_view$", + "(?i)^se_vector_styles$", + "(?i)^se_vector_styles_view$", + "(?i)^spatialindex$", + "(?i)^spatialite_history$", + "(?i)^spatial_ref_sys$", + "(?i)^spatial_ref_sys_all$", + "(?i)^spatial_ref_sys_aux$", + "(?i)^sql_statements_log$", + "(?i)^stored_procedures$", + "(?i)^stored_variables$", + "(?i)^topologies$", + "(?i)^vector_coverages$", + "(?i)^vector_coverages_keyword$", + "(?i)^vector_coverages_ref_sys$", + "(?i)^vector_coverages_srid$", + "(?i)^vector_layers$", + "(?i)^vector_layers_auth$", + "(?i)^vector_layers_field_infos$", + "(?i)^vector_layers_statistics$", + "(?i)^views_geometry_columns$", + "(?i)^views_geometry_columns_auth$", + "(?i)^views_geometry_columns_field_infos$", + "(?i)^views_geometry_columns_statistics$", + "(?i)^virts_geometry_collection$", + "(?i)^virts_geometry_collectionm$", + "(?i)^virts_geometry_columns$", + "(?i)^virts_geometry_columns_auth$", + "(?i)^virts_geometry_columns_field_infos$", + "(?i)^virts_geometry_columns_statistics$", + "(?i)^wms_getcapabilities$", + "(?i)^wms_getmap$", + "(?i)^wms_ref_sys$", + "(?i)^wms_settings$", + ]) + .unwrap() +}); diff --git a/schema-engine/sql-schema-describer/tests/describers/mssql_describer_tests.rs b/schema-engine/sql-schema-describer/tests/describers/mssql_describer_tests.rs index e875648e5902..4db9b4cdfa2c 100644 --- a/schema-engine/sql-schema-describer/tests/describers/mssql_describer_tests.rs +++ b/schema-engine/sql-schema-describer/tests/describers/mssql_describer_tests.rs @@ -121,6 +121,8 @@ fn all_mssql_column_types_must_work(api: TestApi) { [varbinary_max_col] varbinary(max), [image_col] image, [xml_col] xml, + [geometry_col] geometry, + [geography_col] geography, CONSTRAINT "thepk" PRIMARY KEY (primary_col) ); "#; @@ -667,6 +669,42 @@ fn all_mssql_column_types_must_work(api: TestApi) { description: None, }, ), + ( + TableId( + 0, + ), + Column { + name: "geometry_col", + tpe: ColumnType { + full_data_type: "geometry", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "geography_col", + tpe: ColumnType { + full_data_type: "geography", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), ], foreign_keys: [], table_default_values: [], diff --git a/schema-engine/sql-schema-describer/tests/describers/mysql_describer_tests.rs b/schema-engine/sql-schema-describer/tests/describers/mysql_describer_tests.rs index f0ce2833988e..4725b490f316 100644 --- a/schema-engine/sql-schema-describer/tests/describers/mysql_describer_tests.rs +++ b/schema-engine/sql-schema-describer/tests/describers/mysql_describer_tests.rs @@ -674,11 +674,11 @@ fn all_mysql_column_types_must_work(api: TestApi) { name: "geometry_col", tpe: ColumnType { full_data_type: "geometry", - family: Unsupported( - "geometry", - ), + family: Geometry, arity: Nullable, - native_type: None, + native_type: Some( + NativeTypeInstance(..), + ), }, auto_increment: false, description: None, @@ -692,11 +692,11 @@ fn all_mysql_column_types_must_work(api: TestApi) { name: "point_col", tpe: ColumnType { full_data_type: "point", - family: Unsupported( - "point", - ), + family: Geometry, arity: Nullable, - native_type: None, + native_type: Some( + NativeTypeInstance(..), + ), }, auto_increment: false, description: None, @@ -710,11 +710,11 @@ fn all_mysql_column_types_must_work(api: TestApi) { name: "linestring_col", tpe: ColumnType { full_data_type: "linestring", - family: Unsupported( - "linestring", - ), + family: Geometry, arity: Nullable, - native_type: None, + native_type: Some( + NativeTypeInstance(..), + ), }, auto_increment: false, description: None, @@ -728,11 +728,11 @@ fn all_mysql_column_types_must_work(api: TestApi) { name: "polygon_col", tpe: ColumnType { full_data_type: "polygon", - family: Unsupported( - "polygon", - ), + family: Geometry, arity: Nullable, - native_type: None, + native_type: Some( + NativeTypeInstance(..), + ), }, auto_increment: false, description: None, @@ -746,11 +746,11 @@ fn all_mysql_column_types_must_work(api: TestApi) { name: "multipoint_col", tpe: ColumnType { full_data_type: "multipoint", - family: Unsupported( - "multipoint", - ), + family: Geometry, arity: Nullable, - native_type: None, + native_type: Some( + NativeTypeInstance(..), + ), }, auto_increment: false, description: None, @@ -764,11 +764,11 @@ fn all_mysql_column_types_must_work(api: TestApi) { name: "multilinestring_col", tpe: ColumnType { full_data_type: "multilinestring", - family: Unsupported( - "multilinestring", - ), + family: Geometry, arity: Nullable, - native_type: None, + native_type: Some( + NativeTypeInstance(..), + ), }, auto_increment: false, description: None, @@ -782,11 +782,11 @@ fn all_mysql_column_types_must_work(api: TestApi) { name: "multipolygon_col", tpe: ColumnType { full_data_type: "multipolygon", - family: Unsupported( - "multipolygon", - ), + family: Geometry, arity: Nullable, - native_type: None, + native_type: Some( + NativeTypeInstance(..), + ), }, auto_increment: false, description: None, @@ -800,11 +800,11 @@ fn all_mysql_column_types_must_work(api: TestApi) { name: "geometrycollection_col", tpe: ColumnType { full_data_type: "geometrycollection", - family: Unsupported( - "geometrycollection", - ), + family: Geometry, arity: Nullable, - native_type: None, + native_type: Some( + NativeTypeInstance(..), + ), }, auto_increment: false, description: None, @@ -1510,11 +1510,11 @@ fn all_mariadb_column_types_must_work(api: TestApi) { name: "geometry_col", tpe: ColumnType { full_data_type: "geometry", - family: Unsupported( - "geometry", - ), + family: Geometry, arity: Required, - native_type: None, + native_type: Some( + NativeTypeInstance(..), + ), }, auto_increment: false, description: None, @@ -1528,11 +1528,11 @@ fn all_mariadb_column_types_must_work(api: TestApi) { name: "point_col", tpe: ColumnType { full_data_type: "point", - family: Unsupported( - "point", - ), + family: Geometry, arity: Required, - native_type: None, + native_type: Some( + NativeTypeInstance(..), + ), }, auto_increment: false, description: None, @@ -1546,11 +1546,11 @@ fn all_mariadb_column_types_must_work(api: TestApi) { name: "linestring_col", tpe: ColumnType { full_data_type: "linestring", - family: Unsupported( - "linestring", - ), + family: Geometry, arity: Required, - native_type: None, + native_type: Some( + NativeTypeInstance(..), + ), }, auto_increment: false, description: None, @@ -1564,11 +1564,11 @@ fn all_mariadb_column_types_must_work(api: TestApi) { name: "polygon_col", tpe: ColumnType { full_data_type: "polygon", - family: Unsupported( - "polygon", - ), + family: Geometry, arity: Required, - native_type: None, + native_type: Some( + NativeTypeInstance(..), + ), }, auto_increment: false, description: None, @@ -1582,11 +1582,11 @@ fn all_mariadb_column_types_must_work(api: TestApi) { name: "multipoint_col", tpe: ColumnType { full_data_type: "multipoint", - family: Unsupported( - "multipoint", - ), + family: Geometry, arity: Required, - native_type: None, + native_type: Some( + NativeTypeInstance(..), + ), }, auto_increment: false, description: None, @@ -1600,11 +1600,11 @@ fn all_mariadb_column_types_must_work(api: TestApi) { name: "multilinestring_col", tpe: ColumnType { full_data_type: "multilinestring", - family: Unsupported( - "multilinestring", - ), + family: Geometry, arity: Required, - native_type: None, + native_type: Some( + NativeTypeInstance(..), + ), }, auto_increment: false, description: None, @@ -1618,11 +1618,11 @@ fn all_mariadb_column_types_must_work(api: TestApi) { name: "multipolygon_col", tpe: ColumnType { full_data_type: "multipolygon", - family: Unsupported( - "multipolygon", - ), + family: Geometry, arity: Required, - native_type: None, + native_type: Some( + NativeTypeInstance(..), + ), }, auto_increment: false, description: None, @@ -1636,11 +1636,11 @@ fn all_mariadb_column_types_must_work(api: TestApi) { name: "geometrycollection_col", tpe: ColumnType { full_data_type: "geometrycollection", - family: Unsupported( - "geometrycollection", - ), + family: Geometry, arity: Required, - native_type: None, + native_type: Some( + NativeTypeInstance(..), + ), }, auto_increment: false, description: None, @@ -1737,14 +1737,14 @@ fn all_mysql_8_column_types_must_work(api: TestApi) { `tinyblob_col` tinyblob NOT NULL, `mediumblob_col` mediumblob NOT NULL, `longblob_col` longblob NOT NULL, - `geometry_col` geometry NOT NULL, - `point_col` point NOT NULL, - `linestring_col` linestring NOT NULL, - `polygon_col` polygon NOT NULL, - `multipoint_col` multipoint NOT NULL, - `multilinestring_col` multilinestring NOT NULL, - `multipolygon_col` multipolygon NOT NULL, - `geometrycollection_col` geometrycollection NOT NULL, + `geometry_col` geometry srid 4326 NOT NULL, + `point_col` point srid 4326 NOT NULL, + `linestring_col` linestring srid 4326 NOT NULL, + `polygon_col` polygon srid 4326 NOT NULL, + `multipoint_col` multipoint srid 4326 NOT NULL, + `multilinestring_col` multilinestring srid 4326 NOT NULL, + `multipolygon_col` multipolygon srid 4326 NOT NULL, + `geometrycollection_col` geometrycollection srid 4326 NOT NULL, `json_col` json NOT NULL ); @@ -2339,11 +2339,11 @@ fn all_mysql_8_column_types_must_work(api: TestApi) { name: "geometry_col", tpe: ColumnType { full_data_type: "geometry", - family: Unsupported( - "geometry", - ), + family: Geometry, arity: Required, - native_type: None, + native_type: Some( + NativeTypeInstance(..), + ), }, auto_increment: false, description: None, @@ -2357,11 +2357,11 @@ fn all_mysql_8_column_types_must_work(api: TestApi) { name: "point_col", tpe: ColumnType { full_data_type: "point", - family: Unsupported( - "point", - ), + family: Geometry, arity: Required, - native_type: None, + native_type: Some( + NativeTypeInstance(..), + ), }, auto_increment: false, description: None, @@ -2375,11 +2375,11 @@ fn all_mysql_8_column_types_must_work(api: TestApi) { name: "linestring_col", tpe: ColumnType { full_data_type: "linestring", - family: Unsupported( - "linestring", - ), + family: Geometry, arity: Required, - native_type: None, + native_type: Some( + NativeTypeInstance(..), + ), }, auto_increment: false, description: None, @@ -2393,11 +2393,11 @@ fn all_mysql_8_column_types_must_work(api: TestApi) { name: "polygon_col", tpe: ColumnType { full_data_type: "polygon", - family: Unsupported( - "polygon", - ), + family: Geometry, arity: Required, - native_type: None, + native_type: Some( + NativeTypeInstance(..), + ), }, auto_increment: false, description: None, @@ -2411,11 +2411,11 @@ fn all_mysql_8_column_types_must_work(api: TestApi) { name: "multipoint_col", tpe: ColumnType { full_data_type: "multipoint", - family: Unsupported( - "multipoint", - ), + family: Geometry, arity: Required, - native_type: None, + native_type: Some( + NativeTypeInstance(..), + ), }, auto_increment: false, description: None, @@ -2429,11 +2429,11 @@ fn all_mysql_8_column_types_must_work(api: TestApi) { name: "multilinestring_col", tpe: ColumnType { full_data_type: "multilinestring", - family: Unsupported( - "multilinestring", - ), + family: Geometry, arity: Required, - native_type: None, + native_type: Some( + NativeTypeInstance(..), + ), }, auto_increment: false, description: None, @@ -2447,11 +2447,11 @@ fn all_mysql_8_column_types_must_work(api: TestApi) { name: "multipolygon_col", tpe: ColumnType { full_data_type: "multipolygon", - family: Unsupported( - "multipolygon", - ), + family: Geometry, arity: Required, - native_type: None, + native_type: Some( + NativeTypeInstance(..), + ), }, auto_increment: false, description: None, @@ -2465,11 +2465,11 @@ fn all_mysql_8_column_types_must_work(api: TestApi) { name: "geometrycollection_col", tpe: ColumnType { full_data_type: "geomcollection", - family: Unsupported( - "geomcollection", - ), + family: Geometry, arity: Required, - native_type: None, + native_type: Some( + NativeTypeInstance(..), + ), }, auto_increment: false, description: None, diff --git a/schema-engine/sql-schema-describer/tests/describers/postgres_describer_tests.rs b/schema-engine/sql-schema-describer/tests/describers/postgres_describer_tests.rs index 0ce7cee65812..bf785650ec38 100644 --- a/schema-engine/sql-schema-describer/tests/describers/postgres_describer_tests.rs +++ b/schema-engine/sql-schema-describer/tests/describers/postgres_describer_tests.rs @@ -60,7 +60,7 @@ fn postgres_many_namespaces(api: TestApi) { .assert_namespace("three"); } -#[test_connector(tags(Postgres), exclude(CockroachDb))] +#[test_connector(tags(Postgres), exclude(PostGIS, CockroachDb))] fn views_can_be_described(api: TestApi) { let full_sql = r#" CREATE TABLE a (a_id int); @@ -78,7 +78,7 @@ fn views_can_be_described(api: TestApi) { assert_eq!(expected_sql, view.definition.unwrap()); } -#[test_connector(tags(Postgres), exclude(CockroachDb))] +#[test_connector(tags(Postgres), exclude(PostGIS, CockroachDb))] fn all_postgres_column_types_must_work(api: TestApi) { let sql = r#" CREATE TABLE "User" ( @@ -1104,6 +1104,201 @@ fn all_postgres_column_types_must_work(api: TestApi) { expected_ext.assert_debug_eq(&ext); } +#[test_connector(tags(PostGIS), exclude(CockroachDb))] +fn all_postgis_column_types_must_work(api: TestApi) { + let sql = r#" + CREATE EXTENSION IF NOT EXISTS postgis; + + CREATE TABLE "Spatial" ( + geometry_geometry GEOMETRY(GEOMETRY, 3857), + geometry_geometry_z GEOMETRY(GEOMETRYZ, 3857), + geometry_geometry_m GEOMETRY(GEOMETRYM, 3857), + geometry_geometry_zm GEOMETRY(GEOMETRYZM, 3857), + geometry_point GEOMETRY(POINT, 3857), + geometry_point_z GEOMETRY(POINTZ, 3857), + geometry_point_m GEOMETRY(POINTM, 3857), + geometry_point_zm GEOMETRY(POINTZM, 3857), + geometry_line GEOMETRY(LINESTRING, 3857), + geometry_line_z GEOMETRY(LINESTRINGZ, 3857), + geometry_line_m GEOMETRY(LINESTRINGM, 3857), + geometry_line_zm GEOMETRY(LINESTRINGZM, 3857), + geometry_polygon GEOMETRY(POLYGON, 3857), + geometry_polygon_z GEOMETRY(POLYGONZ, 3857), + geometry_polygon_m GEOMETRY(POLYGONM, 3857), + geometry_polygon_zm GEOMETRY(POLYGONZM, 3857), + geometry_multipoint GEOMETRY(MULTIPOINT, 3857), + geometry_multipoint_z GEOMETRY(MULTIPOINTZ, 3857), + geometry_multipoint_m GEOMETRY(MULTIPOINTM, 3857), + geometry_multipoint_zm GEOMETRY(MULTIPOINTZM, 3857), + geometry_multiline GEOMETRY(MULTILINESTRING, 3857), + geometry_multiline_z GEOMETRY(MULTILINESTRINGZ, 3857), + geometry_multiline_m GEOMETRY(MULTILINESTRINGM, 3857), + geometry_multiline_zm GEOMETRY(MULTILINESTRINGZM, 3857), + geometry_multipolygon GEOMETRY(MULTIPOLYGON, 3857), + geometry_multipolygon_z GEOMETRY(MULTIPOLYGONZ, 3857), + geometry_multipolygon_m GEOMETRY(MULTIPOLYGONM, 3857), + geometry_multipolygon_zm GEOMETRY(MULTIPOLYGONZM, 3857), + geometry_collection GEOMETRY(GEOMETRYCOLLECTION, 3857), + geometry_collection_z GEOMETRY(GEOMETRYCOLLECTIONZ, 3857), + geometry_collection_m GEOMETRY(GEOMETRYCOLLECTIONM, 3857), + geometry_collection_zm GEOMETRY(GEOMETRYCOLLECTIONZM, 3857), + geometry_triangle GEOMETRY(TRIANGLE, 3857), + geometry_triangle_z GEOMETRY(TRIANGLEZ, 3857), + geometry_triangle_m GEOMETRY(TRIANGLEM, 3857), + geometry_triangle_zm GEOMETRY(TRIANGLEZM, 3857), + geometry_circularstring GEOMETRY(CIRCULARSTRING, 3857), + geometry_circularstring_z GEOMETRY(CIRCULARSTRINGZ, 3857), + geometry_circularstring_m GEOMETRY(CIRCULARSTRINGM, 3857), + geometry_circularstring_zm GEOMETRY(CIRCULARSTRINGZM, 3857), + geometry_compoundcurve GEOMETRY(COMPOUNDCURVE, 3857), + geometry_compoundcurve_z GEOMETRY(COMPOUNDCURVEZ, 3857), + geometry_compoundcurve_m GEOMETRY(COMPOUNDCURVEM, 3857), + geometry_compoundcurve_zm GEOMETRY(COMPOUNDCURVEZM, 3857), + geometry_curvepolygon GEOMETRY(CURVEPOLYGON, 3857), + geometry_curvepolygon_z GEOMETRY(CURVEPOLYGONZ, 3857), + geometry_curvepolygon_m GEOMETRY(CURVEPOLYGONM, 3857), + geometry_curvepolygon_zm GEOMETRY(CURVEPOLYGONZM, 3857), + geometry_multicurve GEOMETRY(MULTICURVE, 3857), + geometry_multicurve_z GEOMETRY(MULTICURVEZ, 3857), + geometry_multicurve_m GEOMETRY(MULTICURVEM, 3857), + geometry_multicurve_zm GEOMETRY(MULTICURVEZM, 3857), + geometry_multisurface GEOMETRY(MULTISURFACE, 3857), + geometry_multisurface_z GEOMETRY(MULTISURFACEZ, 3857), + geometry_multisurface_m GEOMETRY(MULTISURFACEM, 3857), + geometry_multisurface_zm GEOMETRY(MULTISURFACEZM, 3857), + geometry_polyhedral GEOMETRY(POLYHEDRALSURFACE, 3857), + geometry_polyhedral_z GEOMETRY(POLYHEDRALSURFACEZ, 3857), + geometry_polyhedral_m GEOMETRY(POLYHEDRALSURFACEM, 3857), + geometry_polyhedral_zm GEOMETRY(POLYHEDRALSURFACEZM, 3857), + geometry_tin GEOMETRY(TIN, 3857), + geometry_tin_z GEOMETRY(TINZ, 3857), + geometry_tin_m GEOMETRY(TINM, 3857), + geometry_tin_zm GEOMETRY(TINZM, 3857), + geography_geometry GEOGRAPHY(GEOMETRY, 9000), + geography_geometry_z GEOGRAPHY(GEOMETRYZ, 9000), + geography_geometry_m GEOGRAPHY(GEOMETRYM, 9000), + geography_geometry_zm GEOGRAPHY(GEOMETRYZM, 9000), + geography_point GEOGRAPHY(POINT, 9000), + geography_point_z GEOGRAPHY(POINTZ, 9000), + geography_point_m GEOGRAPHY(POINTM, 9000), + geography_point_zm GEOGRAPHY(POINTZM, 9000), + geography_line GEOGRAPHY(LINESTRING, 9000), + geography_line_z GEOGRAPHY(LINESTRINGZ, 9000), + geography_line_m GEOGRAPHY(LINESTRINGM, 9000), + geography_line_zm GEOGRAPHY(LINESTRINGZM, 9000), + geography_polygon GEOGRAPHY(POLYGON, 9000), + geography_polygon_z GEOGRAPHY(POLYGONZ, 9000), + geography_polygon_m GEOGRAPHY(POLYGONM, 9000), + geography_polygon_zm GEOGRAPHY(POLYGONZM, 9000), + geography_multipoint GEOGRAPHY(MULTIPOINT, 9000), + geography_multipoint_z GEOGRAPHY(MULTIPOINTZ, 9000), + geography_multipoint_m GEOGRAPHY(MULTIPOINTM, 9000), + geography_multipoint_zm GEOGRAPHY(MULTIPOINTZM, 9000), + geography_multiline GEOGRAPHY(MULTILINESTRING, 9000), + geography_multiline_z GEOGRAPHY(MULTILINESTRINGZ, 9000), + geography_multiline_m GEOGRAPHY(MULTILINESTRINGM, 9000), + geography_multiline_zm GEOGRAPHY(MULTILINESTRINGZM, 9000), + geography_multipolygon GEOGRAPHY(MULTIPOLYGON, 9000), + geography_multipolygon_z GEOGRAPHY(MULTIPOLYGONZ, 9000), + geography_multipolygon_m GEOGRAPHY(MULTIPOLYGONM, 9000), + geography_multipolygon_zm GEOGRAPHY(MULTIPOLYGONZM, 9000), + geography_collection GEOGRAPHY(GEOMETRYCOLLECTION, 9000), + geography_collection_z GEOGRAPHY(GEOMETRYCOLLECTIONZ, 9000), + geography_collection_m GEOGRAPHY(GEOMETRYCOLLECTIONM, 9000), + geography_collection_zm GEOGRAPHY(GEOMETRYCOLLECTIONZM, 9000), + geography_triangle GEOGRAPHY(TRIANGLE, 9000), + geography_triangle_z GEOGRAPHY(TRIANGLEZ, 9000), + geography_triangle_m GEOGRAPHY(TRIANGLEM, 9000), + geography_triangle_zm GEOGRAPHY(TRIANGLEZM, 9000), + geography_circularstring GEOGRAPHY(CIRCULARSTRING, 9000), + geography_circularstring_z GEOGRAPHY(CIRCULARSTRINGZ, 9000), + geography_circularstring_m GEOGRAPHY(CIRCULARSTRINGM, 9000), + geography_circularstring_zm GEOGRAPHY(CIRCULARSTRINGZM, 9000), + geography_compoundcurve GEOGRAPHY(COMPOUNDCURVE, 9000), + geography_compoundcurve_z GEOGRAPHY(COMPOUNDCURVEZ, 9000), + geography_compoundcurve_m GEOGRAPHY(COMPOUNDCURVEM, 9000), + geography_compoundcurve_zm GEOGRAPHY(COMPOUNDCURVEZM, 9000), + geography_curvepolygon GEOGRAPHY(CURVEPOLYGON, 9000), + geography_curvepolygon_z GEOGRAPHY(CURVEPOLYGONZ, 9000), + geography_curvepolygon_m GEOGRAPHY(CURVEPOLYGONM, 9000), + geography_curvepolygon_zm GEOGRAPHY(CURVEPOLYGONZM, 9000), + geography_multicurve GEOGRAPHY(MULTICURVE, 9000), + geography_multicurve_z GEOGRAPHY(MULTICURVEZ, 9000), + geography_multicurve_m GEOGRAPHY(MULTICURVEM, 9000), + geography_multicurve_zm GEOGRAPHY(MULTICURVEZM, 9000), + geography_multisurface GEOGRAPHY(MULTISURFACE, 9000), + geography_multisurface_z GEOGRAPHY(MULTISURFACEZ, 9000), + geography_multisurface_m GEOGRAPHY(MULTISURFACEM, 9000), + geography_multisurface_zm GEOGRAPHY(MULTISURFACEZM, 9000), + geography_polyhedral GEOGRAPHY(POLYHEDRALSURFACE, 9000), + geography_polyhedral_z GEOGRAPHY(POLYHEDRALSURFACEZ, 9000), + geography_polyhedral_m GEOGRAPHY(POLYHEDRALSURFACEM, 9000), + geography_polyhedral_zm GEOGRAPHY(POLYHEDRALSURFACEZM, 9000), + geography_tin GEOGRAPHY(TIN, 9000), + geography_tin_z GEOGRAPHY(TINZ, 9000), + geography_tin_m GEOGRAPHY(TINM, 9000), + geography_tin_zm GEOGRAPHY(TINZM, 9000) + ); + "#; + api.raw_cmd(sql); + // TODO@geometry: FIXME! The shema returned contains EVERY PostGIS functions / procedures, tables, views etc + // It is massive. Is there a way to strip it so we can make this test work ? + // let expectation = expect![[r#""#]]; + // api.expect_schema(expectation); + + if api.connector_tags().contains(Tags::Postgres9) { + return; // sequence max values work differently on postgres 9 + } + + let result = api.describe(); + let ext = extract_ext(&result); + let expected_ext = expect![[r#" + PostgresSchemaExt { + opclasses: [], + indexes: [ + ( + IndexId( + 0, + ), + BTree, + ), + ], + expression_indexes: [], + index_null_position: {}, + constraint_options: { + Index( + IndexId( + 0, + ), + ): BitFlags { + bits: 0b0, + }, + }, + table_options: [ + {}, + {}, + ], + exclude_constraints: [], + sequences: [], + extensions: [ + DatabaseExtension { + name: "plpgsql", + schema: "pg_catalog", + version: "1.0", + relocatable: false, + }, + DatabaseExtension { + name: "postgis", + schema: "prisma-tests", + version: "3.3.4", + relocatable: false, + }, + ], + } + "#]]; + expected_ext.assert_debug_eq(&ext); +} + #[test_connector(tags(Postgres))] fn cross_schema_references_are_not_allowed(api: TestApi) { let schema2 = format!("{}_2", api.schema_name()); 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 ccbac9fdc7d0..f87fa67aaf09 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 @@ -210,6 +210,339 @@ fn all_cockroach_column_types_must_work(api: TestApi) { }); } +#[test_connector(tags(CockroachDb))] +fn all_postgis_column_types_must_work(api: TestApi) { + let migration = r#" + CREATE TABLE "Spatial" ( + geometry_geometry GEOMETRY(GEOMETRY, 3857), + geometry_geometry_m GEOMETRY(GEOMETRYZ, 3857), + geometry_geometry_z GEOMETRY(GEOMETRYM, 3857), + geometry_geometry_zm GEOMETRY(GEOMETRYZM, 3857), + geometry_point GEOMETRY(POINT, 3857), + geometry_point_m GEOMETRY(POINTZ, 3857), + geometry_point_z GEOMETRY(POINTM, 3857), + geometry_point_zm GEOMETRY(POINTZM, 3857), + geometry_line GEOMETRY(LINESTRING, 3857), + geometry_line_m GEOMETRY(LINESTRINGZ, 3857), + geometry_line_z GEOMETRY(LINESTRINGM, 3857), + geometry_line_zm GEOMETRY(LINESTRINGZM, 3857), + geometry_polygon GEOMETRY(POLYGON, 3857), + geometry_polygon_m GEOMETRY(POLYGONZ, 3857), + geometry_polygon_z GEOMETRY(POLYGONM, 3857), + geometry_polygon_zm GEOMETRY(POLYGONZM, 3857), + geometry_multipoint GEOMETRY(MULTIPOINT, 3857), + geometry_multipoint_m GEOMETRY(MULTIPOINTZ, 3857), + geometry_multipoint_z GEOMETRY(MULTIPOINTM, 3857), + geometry_multipoint_zm GEOMETRY(MULTIPOINTZM, 3857), + geometry_multiline GEOMETRY(MULTILINESTRING, 3857), + geometry_multiline_m GEOMETRY(MULTILINESTRINGZ, 3857), + geometry_multiline_z GEOMETRY(MULTILINESTRINGM, 3857), + geometry_multiline_zm GEOMETRY(MULTILINESTRINGZM, 3857), + geometry_multipolygon GEOMETRY(MULTIPOLYGON, 3857), + geometry_multipolygon_m GEOMETRY(MULTIPOLYGONZ, 3857), + geometry_multipolygon_z GEOMETRY(MULTIPOLYGONM, 3857), + geometry_multipolygon_zm GEOMETRY(MULTIPOLYGONZM, 3857), + geometry_collection GEOMETRY(GEOMETRYCOLLECTION, 3857), + geometry_collection_m GEOMETRY(GEOMETRYCOLLECTIONZ, 3857), + geometry_collection_z GEOMETRY(GEOMETRYCOLLECTIONM, 3857), + geometry_collection_zm GEOMETRY(GEOMETRYCOLLECTIONZM, 3857), + geography_geometry GEOGRAPHY(GEOMETRY, 9000), + geography_geometry_m GEOGRAPHY(GEOMETRYZ, 9000), + geography_geometry_z GEOGRAPHY(GEOMETRYM, 9000), + geography_geometry_zm GEOGRAPHY(GEOMETRYZM, 9000), + geography_point GEOGRAPHY(POINT, 9000), + geography_point_m GEOGRAPHY(POINTZ, 9000), + geography_point_z GEOGRAPHY(POINTM, 9000), + geography_point_zm GEOGRAPHY(POINTZM, 9000), + geography_line GEOGRAPHY(LINESTRING, 9000), + geography_line_m GEOGRAPHY(LINESTRINGZ, 9000), + geography_line_z GEOGRAPHY(LINESTRINGM, 9000), + geography_line_zm GEOGRAPHY(LINESTRINGZM, 9000), + geography_polygon GEOGRAPHY(POLYGON, 9000), + geography_polygon_m GEOGRAPHY(POLYGONZ, 9000), + geography_polygon_z GEOGRAPHY(POLYGONM, 9000), + geography_polygon_zm GEOGRAPHY(POLYGONZM, 9000), + geography_multipoint GEOGRAPHY(MULTIPOINT, 9000), + geography_multipoint_m GEOGRAPHY(MULTIPOINTZ, 9000), + geography_multipoint_z GEOGRAPHY(MULTIPOINTM, 9000), + geography_multipoint_zm GEOGRAPHY(MULTIPOINTZM, 9000), + geography_multiline GEOGRAPHY(MULTILINESTRING, 9000), + geography_multiline_m GEOGRAPHY(MULTILINESTRINGZ, 9000), + geography_multiline_z GEOGRAPHY(MULTILINESTRINGM, 9000), + geography_multiline_zm GEOGRAPHY(MULTILINESTRINGZM, 9000), + geography_multipolygon GEOGRAPHY(MULTIPOLYGON, 9000), + geography_multipolygon_m GEOGRAPHY(MULTIPOLYGONZ, 9000), + geography_multipolygon_z GEOGRAPHY(MULTIPOLYGONM, 9000), + geography_multipolygon_zm GEOGRAPHY(MULTIPOLYGONZM, 9000), + geography_collection GEOGRAPHY(GEOMETRYCOLLECTION, 9000), + geography_collection_m GEOGRAPHY(GEOMETRYCOLLECTIONZ, 9000), + geography_collection_z GEOGRAPHY(GEOMETRYCOLLECTIONM, 9000), + geography_collection_zm GEOGRAPHY(GEOMETRYCOLLECTIONZM, 9000) + ); + "#; + + api.raw_cmd(migration); + + api.describe().assert_table("Spatial", |t| { + t.assert_column("geometry_geometry", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_geometry_z", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_geometry_m", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_geometry_zm", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_point", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_point_z", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_point_m", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_point_zm", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_line", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_line_z", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_line_m", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_line_zm", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_polygon", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_polygon_z", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_polygon_m", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_polygon_zm", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_multipoint", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_multipoint_z", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_multipoint_m", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_multipoint_zm", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_multiline", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_multiline_z", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_multiline_m", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_multiline_zm", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_multipolygon", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_multipolygon_z", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_multipolygon_m", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_multipolygon_zm", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_collection", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_collection_z", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_collection_m", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geometry_collection_zm", |c| { + c.assert_full_data_type("geometry") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_geometry", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_geometry_z", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_geometry_m", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_geometry_zm", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_point", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_point_z", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_point_m", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_point_zm", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_line", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_line_z", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_line_m", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_line_zm", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_polygon", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_polygon_z", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_polygon_m", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_polygon_zm", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_multipoint", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_multipoint_z", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_multipoint_m", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_multipoint_zm", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_multiline", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_multiline_z", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_multiline_m", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_multiline_zm", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_multipolygon", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_multipolygon_z", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_multipolygon_m", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_multipolygon_zm", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_collection", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_collection_z", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_collection_m", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + .assert_column("geography_collection_zm", |c| { + c.assert_full_data_type("geography") + .assert_column_type_family(ColumnTypeFamily::Geometry) + }) + }); +} + #[test_connector(tags(CockroachDb))] fn multi_field_indexes_must_be_inferred_in_the_right_order(api: TestApi) { let schema = format!( diff --git a/schema-engine/sql-schema-describer/tests/describers/sqlite_describer_tests.rs b/schema-engine/sql-schema-describer/tests/describers/sqlite_describer_tests.rs index a7928af66edc..7528742f95dd 100644 --- a/schema-engine/sql-schema-describer/tests/describers/sqlite_describer_tests.rs +++ b/schema-engine/sql-schema-describer/tests/describers/sqlite_describer_tests.rs @@ -51,7 +51,7 @@ fn views_can_be_described(api: TestApi) { fn sqlite_column_types_must_work(api: TestApi) { let sql = r#" CREATE TABLE "User" ( - int_col int not null, + int_col int NOT NULL, int4_col INTEGER NOT NULL, text_col TEXT NOT NULL, real_col REAL NOT NULL, @@ -211,6 +211,697 @@ fn sqlite_column_types_must_work(api: TestApi) { api.expect_schema(expectation); } +#[test_connector(tags(Spatialite))] +fn spatialite_column_types_must_work(api: TestApi) { + let sql = r#" + SELECT InitSpatialMetaData(); + + CREATE TABLE "User" ( + primary_col INTEGER PRIMARY KEY + ); + + SELECT + AddGeometryColumn('User', 'geometry_xy', 3857, 'GEOMETRY', 'XY', 0), + AddGeometryColumn('User', 'geometry_xyz', 3857, 'GEOMETRY', 'XYZ', 0), + AddGeometryColumn('User', 'geometry_xym', 3857, 'GEOMETRY', 'XYM', 0), + AddGeometryColumn('User', 'geometry_xyzm', 3857, 'GEOMETRY', 'XYZM', 0), + AddGeometryColumn('User', 'point_xy', 3857, 'POINT', 'XY', 0), + AddGeometryColumn('User', 'point_xyz', 3857, 'POINT', 'XYZ', 0), + AddGeometryColumn('User', 'point_xym', 3857, 'POINT', 'XYM', 0), + AddGeometryColumn('User', 'point_xyzm', 3857, 'POINT', 'XYZM', 0), + AddGeometryColumn('User', 'linestring_xy', 3857, 'LINESTRING', 'XY', 0), + AddGeometryColumn('User', 'linestring_xyz', 3857, 'LINESTRING', 'XYZ', 0), + AddGeometryColumn('User', 'linestring_xym', 3857, 'LINESTRING', 'XYM', 0), + AddGeometryColumn('User', 'linestring_xyzm', 3857, 'LINESTRING', 'XYZM', 0), + AddGeometryColumn('User', 'polygon_xy', 3857, 'POLYGON', 'XY', 0), + AddGeometryColumn('User', 'polygon_xyz', 3857, 'POLYGON', 'XYZ', 0), + AddGeometryColumn('User', 'polygon_xym', 3857, 'POLYGON', 'XYM', 0), + AddGeometryColumn('User', 'polygon_xyzm', 3857, 'POLYGON', 'XYZM', 0), + AddGeometryColumn('User', 'multipoint_xy', 3857, 'MULTIPOINT', 'XY', 0), + AddGeometryColumn('User', 'multipoint_xyz', 3857, 'MULTIPOINT', 'XYZ', 0), + AddGeometryColumn('User', 'multipoint_xym', 3857, 'MULTIPOINT', 'XYM', 0), + AddGeometryColumn('User', 'multipoint_xyzm', 3857, 'MULTIPOINT', 'XYZM', 0), + AddGeometryColumn('User', 'multilinestring_xy', 3857, 'MULTILINESTRING', 'XY', 0), + AddGeometryColumn('User', 'multilinestring_xyz', 3857, 'MULTILINESTRING', 'XYZ', 0), + AddGeometryColumn('User', 'multilinestring_xym', 3857, 'MULTILINESTRING', 'XYM', 0), + AddGeometryColumn('User', 'multilinestring_xyzm', 3857, 'MULTILINESTRING', 'XYZM', 0), + AddGeometryColumn('User', 'multipolygon_xy', 3857, 'MULTIPOLYGON', 'XY', 0), + AddGeometryColumn('User', 'multipolygon_xyz', 3857, 'MULTIPOLYGON', 'XYZ', 0), + AddGeometryColumn('User', 'multipolygon_xym', 3857, 'MULTIPOLYGON', 'XYM', 0), + AddGeometryColumn('User', 'multipolygon_xyzm', 3857, 'MULTIPOLYGON', 'XYZM', 0), + AddGeometryColumn('User', 'geometrycollection_xy', 3857, 'GEOMETRYCOLLECTION', 'XY', 0), + AddGeometryColumn('User', 'geometrycollection_xyz', 3857, 'GEOMETRYCOLLECTION', 'XYZ', 0), + AddGeometryColumn('User', 'geometrycollection_xym', 3857, 'GEOMETRYCOLLECTION', 'XYM', 0), + AddGeometryColumn('User', 'geometrycollection_xyzm', 3857, 'GEOMETRYCOLLECTION', 'XYZM', 0); + "#; + api.raw_cmd(sql); + let expectation = expect![[r#" + SqlSchema { + namespaces: [], + tables: [ + Table { + namespace_id: NamespaceId( + 0, + ), + name: "User", + properties: BitFlags { + bits: 0b0, + }, + description: None, + }, + ], + enums: [], + enum_variants: [], + table_columns: [ + ( + TableId( + 0, + ), + Column { + name: "primary_col", + tpe: ColumnType { + full_data_type: "integer", + family: Int, + arity: Required, + native_type: None, + }, + auto_increment: true, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "geometry_xy", + tpe: ColumnType { + full_data_type: "GEOMETRY", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "geometry_xyz", + tpe: ColumnType { + full_data_type: "GEOMETRY", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "geometry_xym", + tpe: ColumnType { + full_data_type: "GEOMETRY", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "geometry_xyzm", + tpe: ColumnType { + full_data_type: "GEOMETRY", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "point_xy", + tpe: ColumnType { + full_data_type: "POINT", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "point_xyz", + tpe: ColumnType { + full_data_type: "POINT", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "point_xym", + tpe: ColumnType { + full_data_type: "POINT", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "point_xyzm", + tpe: ColumnType { + full_data_type: "POINT", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "linestring_xy", + tpe: ColumnType { + full_data_type: "LINESTRING", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "linestring_xyz", + tpe: ColumnType { + full_data_type: "LINESTRING", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "linestring_xym", + tpe: ColumnType { + full_data_type: "LINESTRING", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "linestring_xyzm", + tpe: ColumnType { + full_data_type: "LINESTRING", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "polygon_xy", + tpe: ColumnType { + full_data_type: "POLYGON", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "polygon_xyz", + tpe: ColumnType { + full_data_type: "POLYGON", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "polygon_xym", + tpe: ColumnType { + full_data_type: "POLYGON", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "polygon_xyzm", + tpe: ColumnType { + full_data_type: "POLYGON", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "multipoint_xy", + tpe: ColumnType { + full_data_type: "MULTIPOINT", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "multipoint_xyz", + tpe: ColumnType { + full_data_type: "MULTIPOINT", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "multipoint_xym", + tpe: ColumnType { + full_data_type: "MULTIPOINT", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "multipoint_xyzm", + tpe: ColumnType { + full_data_type: "MULTIPOINT", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "multilinestring_xy", + tpe: ColumnType { + full_data_type: "MULTILINESTRING", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "multilinestring_xyz", + tpe: ColumnType { + full_data_type: "MULTILINESTRING", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "multilinestring_xym", + tpe: ColumnType { + full_data_type: "MULTILINESTRING", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "multilinestring_xyzm", + tpe: ColumnType { + full_data_type: "MULTILINESTRING", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "multipolygon_xy", + tpe: ColumnType { + full_data_type: "MULTIPOLYGON", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "multipolygon_xyz", + tpe: ColumnType { + full_data_type: "MULTIPOLYGON", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "multipolygon_xym", + tpe: ColumnType { + full_data_type: "MULTIPOLYGON", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "multipolygon_xyzm", + tpe: ColumnType { + full_data_type: "MULTIPOLYGON", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "geometrycollection_xy", + tpe: ColumnType { + full_data_type: "GEOMETRYCOLLECTION", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "geometrycollection_xyz", + tpe: ColumnType { + full_data_type: "GEOMETRYCOLLECTION", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "geometrycollection_xym", + tpe: ColumnType { + full_data_type: "GEOMETRYCOLLECTION", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ( + TableId( + 0, + ), + Column { + name: "geometrycollection_xyzm", + tpe: ColumnType { + full_data_type: "GEOMETRYCOLLECTION", + family: Geometry, + arity: Nullable, + native_type: Some( + NativeTypeInstance(..), + ), + }, + auto_increment: false, + description: None, + }, + ), + ], + foreign_keys: [], + table_default_values: [], + view_default_values: [], + foreign_key_columns: [], + indexes: [ + Index { + table_id: TableId( + 0, + ), + index_name: "", + tpe: PrimaryKey, + }, + ], + index_columns: [ + IndexColumn { + index_id: IndexId( + 0, + ), + column_id: TableColumnId( + 0, + ), + sort_order: None, + length: None, + }, + ], + check_constraints: [], + views: [], + view_columns: [], + procedures: [], + user_defined_types: [], + connector_data: , + } + "#]]; + api.expect_schema(expectation); +} + #[test_connector(tags(Sqlite))] fn sqlite_foreign_key_on_delete_must_be_handled(api: TestApi) { use sql_schema_describer::ForeignKeyAction::*; diff --git a/schema-engine/sql-schema-describer/tests/test_api/mod.rs b/schema-engine/sql-schema-describer/tests/test_api/mod.rs index 17a94589ddbd..68ea95551b8f 100644 --- a/schema-engine/sql-schema-describer/tests/test_api/mod.rs +++ b/schema-engine/sql-schema-describer/tests/test_api/mod.rs @@ -82,16 +82,16 @@ impl TestApi { match self.sql_family() { SqlFamily::Postgres => { use postgres::Circumstances; - sql_schema_describer::postgres::SqlSchemaDescriber::new( - &self.database, - if self.tags.contains(Tags::CockroachDb) { - Circumstances::Cockroach.into() - } else { - Default::default() - }, - ) - .describe(schemas) - .await + let mut circumstances: BitFlags = Default::default(); + if self.tags.contains(Tags::CockroachDb) { + circumstances |= Circumstances::Cockroach + }; + if self.tags.contains(Tags::PostGIS) { + circumstances |= Circumstances::HasPostGIS + }; + sql_schema_describer::postgres::SqlSchemaDescriber::new(&self.database, circumstances) + .describe(schemas) + .await } SqlFamily::Sqlite => { sql_schema_describer::sqlite::SqlSchemaDescriber::new(&self.database) From e605279c9dc7ff404c08b700187a33e21bcd46b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A8le=20Nitoref?= Date: Fri, 8 Sep 2023 20:24:34 +0200 Subject: [PATCH 002/103] chore: add postgis database to query engine test matrix --- .github/workflows/test-query-engine.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/test-query-engine.yml b/.github/workflows/test-query-engine.yml index 24f1032e6929..b86fcbbbab0c 100644 --- a/.github/workflows/test-query-engine.yml +++ b/.github/workflows/test-query-engine.yml @@ -33,6 +33,10 @@ jobs: single_threaded: true connector: 'postgres' version: '15' + - name: 'postgis15' + single_threaded: true + connector: 'postgres' + version: '15-postgis' - name: 'mssql_2022' single_threaded: false connector: 'sqlserver' From 0a750daf017c27d354e126e223c0a3cb9afb6278 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A8le=20Nitoref?= Date: Fri, 8 Sep 2023 21:53:58 +0200 Subject: [PATCH 003/103] fix: mysql geometries should be serialized to wkb by quaint --- quaint/src/visitor/mysql.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/quaint/src/visitor/mysql.rs b/quaint/src/visitor/mysql.rs index 2ab3f08abf0e..1dbd6bca595e 100644 --- a/quaint/src/visitor/mysql.rs +++ b/quaint/src/visitor/mysql.rs @@ -281,6 +281,11 @@ impl<'a> Visitor<'a> for Mysql<'a> { } } + fn visit_parameterized(&mut self, value: Value<'a>) -> visitor::Result { + self.add_parameter(value); + self.parameter_substitution() + } + fn parameter_substitution(&mut self) -> visitor::Result { self.write("?") } From 98440338eb350c28525bbe6b11a551d29b5b53ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A8le=20Nitoref?= Date: Fri, 8 Sep 2023 22:18:01 +0200 Subject: [PATCH 004/103] fix: failing inequality operator with PostGIS --- quaint/src/visitor/postgres.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/quaint/src/visitor/postgres.rs b/quaint/src/visitor/postgres.rs index edc996103c5a..3697ddffd89d 100644 --- a/quaint/src/visitor/postgres.rs +++ b/quaint/src/visitor/postgres.rs @@ -381,6 +381,12 @@ impl<'a> Visitor<'a> for Postgres<'a> { _ => "", }; + // TODO@geometry: file a bug report to PostGIS ? (ERROR: operator is not unique: geometry <> geometry) + if left.is_geometry_expr() && right.is_geometry_expr() { + self.write("NOT ")?; + return self.visit_equals(left, right) + } + self.visit_expression(left)?; self.write(left_cast)?; self.write(" <> ")?; From b267f617bd0b44c02c40cb802782c877cc770d45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A8le=20Nitoref?= Date: Fri, 8 Sep 2023 22:18:53 +0200 Subject: [PATCH 005/103] fix: PostGIS tests need to happen with the public schema exposed --- quaint/src/visitor/postgres.rs | 2 +- .../src/schemas/geometry.rs | 25 -------- .../query-engine-tests/src/schemas/mod.rs | 2 - .../tests/queries/filters/geometry_filter.rs | 59 +++++++++++++++---- .../writes/top_level_mutations/create.rs | 46 ++++++++++++--- 5 files changed, 88 insertions(+), 46 deletions(-) delete mode 100644 query-engine/connector-test-kit-rs/query-engine-tests/src/schemas/geometry.rs diff --git a/quaint/src/visitor/postgres.rs b/quaint/src/visitor/postgres.rs index 3697ddffd89d..7d58f46ee942 100644 --- a/quaint/src/visitor/postgres.rs +++ b/quaint/src/visitor/postgres.rs @@ -384,7 +384,7 @@ impl<'a> Visitor<'a> for Postgres<'a> { // TODO@geometry: file a bug report to PostGIS ? (ERROR: operator is not unique: geometry <> geometry) if left.is_geometry_expr() && right.is_geometry_expr() { self.write("NOT ")?; - return self.visit_equals(left, right) + return self.visit_equals(left, right); } self.visit_expression(left)?; diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/src/schemas/geometry.rs b/query-engine/connector-test-kit-rs/query-engine-tests/src/schemas/geometry.rs deleted file mode 100644 index c52442912461..000000000000 --- a/query-engine/connector-test-kit-rs/query-engine-tests/src/schemas/geometry.rs +++ /dev/null @@ -1,25 +0,0 @@ -use indoc::indoc; - -/// Basic Test model containing a single geometry field. -pub fn geometry() -> String { - let schema = indoc! { - "model TestModel { - #id(id, Int, @id) - geometry GeoJson - }" - }; - - schema.to_owned() -} - -/// Basic Test model containing a single optional geometry field. -pub fn geometry_opt() -> String { - let schema = indoc! { - "model TestModel { - #id(id, Int, @id) - geometry GeoJson? - }" - }; - - schema.to_owned() -} diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/src/schemas/mod.rs b/query-engine/connector-test-kit-rs/query-engine-tests/src/schemas/mod.rs index 797235a679cb..cd9d2d9d1cb2 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/src/schemas/mod.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/src/schemas/mod.rs @@ -1,13 +1,11 @@ mod basic; mod composites; -mod geometry; mod json; mod many_to_many; mod one_to_many; pub use basic::*; pub use composites::*; -pub use geometry::*; pub use json::*; pub use many_to_many::*; pub use one_to_many::*; diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs index fe29e6dc95e2..a2df18b46580 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs @@ -1,10 +1,6 @@ use query_engine_tests::*; -#[test_suite( - schema(schema), - capabilities(GeoJsonGeometry), - exclude(Postgres(9, 10, 11, 12, 13, 14, 15, "pgbouncer")) -)] +#[test_suite(capabilities(GeoJsonGeometry))] mod geometry_filter_spec { use query_engine_tests::run_query; @@ -21,8 +17,21 @@ mod geometry_filter_spec { schema.to_owned() } - #[connector_test] - async fn basic_where(runner: Runner) -> TestResult<()> { + fn schema_postgres() -> String { + let schema = indoc! { + r#" + model TestModel { + @@schema("test") + #id(id, Int, @id) + geom GeoJson? + } + "# + }; + + schema.to_owned() + } + + async fn basic_where_test(runner: Runner) -> TestResult<()> { test_data(&runner).await?; insta::assert_snapshot!( @@ -43,8 +52,7 @@ mod geometry_filter_spec { Ok(()) } - #[connector_test] - async fn where_shorthands(runner: Runner) -> TestResult<()> { + async fn where_shorthands_test(runner: Runner) -> TestResult<()> { test_data(&runner).await?; insta::assert_snapshot!( @@ -63,8 +71,7 @@ mod geometry_filter_spec { Ok(()) } - #[connector_test(capabilities(GeometryFiltering))] - async fn geometric_comparison_filters(runner: Runner) -> TestResult<()> { + async fn geometric_comparison_filters_test(runner: Runner) -> TestResult<()> { test_data(&runner).await?; // geoWithin @@ -94,6 +101,36 @@ mod geometry_filter_spec { Ok(()) } + #[connector_test(schema(schema), exclude(Postgres))] + async fn basic_where(runner: Runner) -> TestResult<()> { + basic_where_test(runner).await + } + + #[connector_test(schema(schema), exclude(Postgres))] + async fn where_shorthands(runner: Runner) -> TestResult<()> { + where_shorthands_test(runner).await + } + + #[connector_test(schema(schema), exclude(Postgres))] + async fn geometric_comparison_filters(runner: Runner) -> TestResult<()> { + geometric_comparison_filters_test(runner).await + } + + #[connector_test(schema(schema_postgres), db_schemas("public", "test"), only(Postgres("15-postgis")))] + async fn basic_where_postgres(runner: Runner) -> TestResult<()> { + basic_where_test(runner).await + } + + #[connector_test(schema(schema_postgres), db_schemas("public", "test"), only(Postgres("15-postgis")))] + async fn where_shorthands_postgres(runner: Runner) -> TestResult<()> { + where_shorthands_test(runner).await + } + + #[connector_test(schema(schema_postgres), db_schemas("public", "test"), only(Postgres("15-postgis")))] + async fn geometric_comparison_filters_postgres(runner: Runner) -> TestResult<()> { + geometric_comparison_filters_test(runner).await + } + async fn test_data(runner: &Runner) -> TestResult<()> { runner .query(indoc! { r#" diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs index d53b98daf871..1e46dc4adafe 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs @@ -425,16 +425,11 @@ mod mapped_create { } } -#[test_suite( - schema(geometry_opt), - capabilities(GeoJsonGeometry), - exclude(Postgres(9, 10, 11, 12, 13, 14, 15, "pgbouncer")) -)] +#[test_suite(capabilities(GeoJsonGeometry))] mod geometry_create { use query_engine_tests::run_query; - #[connector_test] - async fn create_geometry(runner: Runner) -> TestResult<()> { + async fn create_geometry_test(runner: Runner) -> TestResult<()> { // TODO@geometry: ideally, make geojson generation consistent with SQL connectors match_connector_result!( &runner, @@ -456,4 +451,41 @@ mod geometry_create { Ok(()) } + + fn geometry_opt() -> String { + let schema = indoc! { + r#"model TestModel { + #id(id, Int, @id) + geometry GeoJson? + }"# + }; + + schema.to_owned() + } + + fn geometry_opt_postgres() -> String { + let schema = indoc! { + r#"model TestModel { + @@schema("test") + #id(id, Int, @id) + geometry GeoJson? + }"# + }; + + schema.to_owned() + } + + #[connector_test(schema(geometry_opt), exclude(Postgres))] + async fn create_geometry(runner: Runner) -> TestResult<()> { + create_geometry_test(runner).await + } + + #[connector_test( + schema(geometry_opt_postgres), + db_schemas("public", "test"), + only(Postgres("15-postgis")) + )] + async fn create_geometry_postgres(runner: Runner) -> TestResult<()> { + create_geometry_test(runner).await + } } From 2aaf40be898fdb26dad596494b3b8989fb76d608 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A8le=20Nitoref?= Date: Fri, 8 Sep 2023 23:27:15 +0200 Subject: [PATCH 006/103] fix: add missing GeometryFiltering capability constraint to geometric_comparison_filters --- .../query-engine-tests/tests/queries/filters/geometry_filter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs index a2df18b46580..5c857f14290e 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs @@ -111,7 +111,7 @@ mod geometry_filter_spec { where_shorthands_test(runner).await } - #[connector_test(schema(schema), exclude(Postgres))] + #[connector_test(schema(schema), exclude(Postgres), capabilities(GeometryFiltering))] async fn geometric_comparison_filters(runner: Runner) -> TestResult<()> { geometric_comparison_filters_test(runner).await } From b9f411f9c163355e16483c2a295b672fccdfa81c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A8le=20Nitoref?= Date: Sat, 9 Sep 2023 13:00:12 +0200 Subject: [PATCH 007/103] fix: srid introspection in postgres dialect Geography default SRID is 4326 in PG, but 0 in CRDB. But in both cases, if non 0, the column SRID it will be always explicitly mentioned in the type information column. --- schema-engine/sql-schema-describer/src/postgres.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/schema-engine/sql-schema-describer/src/postgres.rs b/schema-engine/sql-schema-describer/src/postgres.rs index 8283acb79b22..58da2d4b83c8 100644 --- a/schema-engine/sql-schema-describer/src/postgres.rs +++ b/schema-engine/sql-schema-describer/src/postgres.rs @@ -985,10 +985,7 @@ impl<'a> SqlSchemaDescriber<'a> { .name("type") .map(|t| GeometryType::from_str(t.as_str())) .unwrap_or(Ok(GeometryType::default())); - let srid = capture - .name("srid") - .map(|v| v.as_str().parse::()) - .unwrap_or(Ok(if is_geography { 4326 } else { 0 })); + let srid = capture.name("srid").map(|v| v.as_str().parse::()).unwrap_or(Ok(0)); match (geom_type, srid) { (Ok(ty), Ok(srid)) => Some(GeometryParams { ty, srid }), _ => None, From f42f3baeee62130f5dff1fd3a32e6cea281b9a42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A8le=20Nitoref?= Date: Sat, 9 Sep 2023 17:21:43 +0200 Subject: [PATCH 008/103] fix: handle geography default srid value inconsistency in tests --- .../tests/native_types/postgres.rs | 68 +++++++++---------- 1 file changed, 32 insertions(+), 36 deletions(-) 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 2ff61e6e3644..edaa48cafcc4 100644 --- a/schema-engine/sql-introspection-tests/tests/native_types/postgres.rs +++ b/schema-engine/sql-introspection-tests/tests/native_types/postgres.rs @@ -39,7 +39,6 @@ const TYPES: &[(&str, &str)] = &[ const GEOMETRY_TYPES: &[(&str, &str)] = &[ ("geometry", "Geometry"), ("geometry_geometry", "Geometry(Geometry)"), - ("geometry_geometry_srid", "Geometry(Geometry, 4326)"), ("geometry_geometry_m", "Geometry(GeometryM)"), ("geometry_geometry_z", "Geometry(GeometryZ)"), ("geometry_geometry_zm", "Geometry(GeometryZM)"), @@ -73,7 +72,6 @@ const GEOMETRY_TYPES: &[(&str, &str)] = &[ ("geometry_geometrycollection_zm", "Geometry(GeometryCollectionZM)"), ("geography", "Geography"), ("geography_geometry", "Geography(Geometry)"), - ("geography_geometry_srid", "Geography(Geometry, 4326)"), ("geography_geometry_m", "Geography(GeometryM)"), ("geography_geometry_z", "Geography(GeometryZ)"), ("geography_geometry_zm", "Geography(GeometryZM)"), @@ -140,38 +138,38 @@ const GEOMETRY_EXTRA_TYPES: &[(&str, &str)] = &[ ("geometry_tinm", "Geometry(TinM)"), ("geometry_tinz", "Geometry(TinZ)"), ("geometry_tinzm", "Geometry(TinZM)"), - ("geography_circularstring", "Geography(CircularString)"), - ("geography_circularstringm", "Geography(CircularStringM)"), - ("geography_circularstringz", "Geography(CircularStringZ)"), - ("geography_circularstringzm", "Geography(CircularStringZM)"), - ("geography_compoundcurve", "Geography(CompoundCurve)"), - ("geography_compoundcurvem", "Geography(CompoundCurveM)"), - ("geography_compoundcurvez", "Geography(CompoundCurveZ)"), - ("geography_compoundcurvezm", "Geography(CompoundCurveZM)"), - ("geography_curvepolygon", "Geography(CurvePolygon)"), - ("geography_curvepolygonm", "Geography(CurvePolygonM)"), - ("geography_curvepolygonz", "Geography(CurvePolygonZ)"), - ("geography_curvepolygonzm", "Geography(CurvePolygonZM)"), - ("geography_multicurve", "Geography(MultiCurve)"), - ("geography_multicurvem", "Geography(MultiCurveM)"), - ("geography_multicurvez", "Geography(MultiCurveZ)"), - ("geography_multicurvezm", "Geography(MultiCurveZM)"), - ("geography_multisurface", "Geography(MultiSurface)"), - ("geography_multisurfacem", "Geography(MultiSurfaceM)"), - ("geography_multisurfacez", "Geography(MultiSurfaceZ)"), - ("geography_multisurfacezm", "Geography(MultiSurfaceZM)"), - ("geography_polyhedralsurface", "Geography(PolyhedralSurface)"), - ("geography_polyhedralsurfacem", "Geography(PolyhedralSurfaceM)"), - ("geography_polyhedralsurfacez", "Geography(PolyhedralSurfaceZ)"), - ("geography_polyhedralsurfacezm", "Geography(PolyhedralSurfaceZM)"), - ("geography_triangle", "Geography(Triangle)"), - ("geography_trianglem", "Geography(TriangleM)"), - ("geography_trianglez", "Geography(TriangleZ)"), - ("geography_trianglezm", "Geography(TriangleZM)"), - ("geography_tin", "Geography(Tin)"), - ("geography_tinm", "Geography(TinM)"), - ("geography_tinz", "Geography(TinZ)"), - ("geography_tinzm", "Geography(TinZM)"), + ("geography_circularstring", "Geography(CircularString, 4326)"), + ("geography_circularstringm", "Geography(CircularStringM, 4326)"), + ("geography_circularstringz", "Geography(CircularStringZ, 4326)"), + ("geography_circularstringzm", "Geography(CircularStringZM, 4326)"), + ("geography_compoundcurve", "Geography(CompoundCurve, 4326)"), + ("geography_compoundcurvem", "Geography(CompoundCurveM, 4326)"), + ("geography_compoundcurvez", "Geography(CompoundCurveZ, 4326)"), + ("geography_compoundcurvezm", "Geography(CompoundCurveZM, 4326)"), + ("geography_curvepolygon", "Geography(CurvePolygon, 4326)"), + ("geography_curvepolygonm", "Geography(CurvePolygonM, 4326)"), + ("geography_curvepolygonz", "Geography(CurvePolygonZ, 4326)"), + ("geography_curvepolygonzm", "Geography(CurvePolygonZM, 4326)"), + ("geography_multicurve", "Geography(MultiCurve, 4326)"), + ("geography_multicurvem", "Geography(MultiCurveM, 4326)"), + ("geography_multicurvez", "Geography(MultiCurveZ, 4326)"), + ("geography_multicurvezm", "Geography(MultiCurveZM, 4326)"), + ("geography_multisurface", "Geography(MultiSurface, 4326)"), + ("geography_multisurfacem", "Geography(MultiSurfaceM, 4326)"), + ("geography_multisurfacez", "Geography(MultiSurfaceZ, 4326)"), + ("geography_multisurfacezm", "Geography(MultiSurfaceZM, 4326)"), + ("geography_polyhedralsurface", "Geography(PolyhedralSurface, 4326)"), + ("geography_polyhedralsurfacem", "Geography(PolyhedralSurfaceM, 4326)"), + ("geography_polyhedralsurfacez", "Geography(PolyhedralSurfaceZ, 4326)"), + ("geography_polyhedralsurfacezm", "Geography(PolyhedralSurfaceZM, 4326)"), + ("geography_triangle", "Geography(Triangle, 4326)"), + ("geography_trianglem", "Geography(TriangleM, 4326)"), + ("geography_trianglez", "Geography(TriangleZ, 4326)"), + ("geography_trianglezm", "Geography(TriangleZM, 4326)"), + ("geography_tin", "Geography(Tin, 4326)"), + ("geography_tinm", "Geography(TinM, 4326)"), + ("geography_tinz", "Geography(TinZ, 4326)"), + ("geography_tinzm", "Geography(TinZM, 4326)"), ]; #[test_connector(tags(Postgres), exclude(PostGIS, CockroachDb))] @@ -263,7 +261,6 @@ async fn native_type_spatial_columns_feature_on(api: &mut TestApi) -> TestResult id Int @id geometry Geometry geometry_geometry Geometry - geometry_geometry_srid Geometry @db.Geometry(Geometry, 4326) geometry_geometry_m Geometry @db.Geometry(GeometryM) geometry_geometry_z Geometry @db.Geometry(GeometryZ) geometry_geometry_zm Geometry @db.Geometry(GeometryZM) @@ -297,7 +294,6 @@ async fn native_type_spatial_columns_feature_on(api: &mut TestApi) -> TestResult geometry_geometrycollection_zm Geometry @db.Geometry(GeometryCollectionZM) geography Geometry @db.Geography(Geometry, 4326) geography_geometry Geometry @db.Geography(Geometry, 4326) - geography_geometry_srid Geometry @db.Geography(Geometry, 4326) geography_geometry_m Geometry @db.Geography(GeometryM, 4326) geography_geometry_z Geometry @db.Geography(GeometryZ, 4326) geography_geometry_zm Geometry @db.Geography(GeometryZM, 4326) From c44ee7a255853be6f0674bafd48bd5bf2aa7ade0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A8le=20Nitoref?= Date: Sat, 9 Sep 2023 17:37:10 +0200 Subject: [PATCH 009/103] fix: remove unused variable --- schema-engine/sql-schema-describer/src/postgres.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/schema-engine/sql-schema-describer/src/postgres.rs b/schema-engine/sql-schema-describer/src/postgres.rs index 58da2d4b83c8..97575a418461 100644 --- a/schema-engine/sql-schema-describer/src/postgres.rs +++ b/schema-engine/sql-schema-describer/src/postgres.rs @@ -980,7 +980,6 @@ impl<'a> SqlSchemaDescriber<'a> { static GEOM_REGEX: Lazy = Lazy::new(|| Regex::new(r"^(?Pgeometry|geography)(\((?P.+?)(,(?P\d+))?\))?$").unwrap()); GEOM_REGEX.captures(col).and_then(|capture| { - let is_geography = capture.name("class").map(|c| c.as_str() == "geography").unwrap(); let geom_type = capture .name("type") .map(|t| GeometryType::from_str(t.as_str())) From c16fcd7ded2759889670c712969be1856b5b33a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A8le=20Nitoref?= Date: Sat, 9 Sep 2023 18:34:27 +0200 Subject: [PATCH 010/103] fix: geography srid introspection test in postgres dialect --- .../tests/native_types/postgres.rs | 70 +++++++++---------- 1 file changed, 34 insertions(+), 36 deletions(-) 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 edaa48cafcc4..cb99c013f524 100644 --- a/schema-engine/sql-introspection-tests/tests/native_types/postgres.rs +++ b/schema-engine/sql-introspection-tests/tests/native_types/postgres.rs @@ -38,7 +38,7 @@ const TYPES: &[(&str, &str)] = &[ const GEOMETRY_TYPES: &[(&str, &str)] = &[ ("geometry", "Geometry"), - ("geometry_geometry", "Geometry(Geometry)"), + ("geometry_srid", "Geometry(Geometry, 3857)"), ("geometry_geometry_m", "Geometry(GeometryM)"), ("geometry_geometry_z", "Geometry(GeometryZ)"), ("geometry_geometry_zm", "Geometry(GeometryZM)"), @@ -70,39 +70,38 @@ const GEOMETRY_TYPES: &[(&str, &str)] = &[ ("geometry_geometrycollection_m", "Geometry(GeometryCollectionM)"), ("geometry_geometrycollection_z", "Geometry(GeometryCollectionZ)"), ("geometry_geometrycollection_zm", "Geometry(GeometryCollectionZM)"), - ("geography", "Geography"), - ("geography_geometry", "Geography(Geometry)"), - ("geography_geometry_m", "Geography(GeometryM)"), - ("geography_geometry_z", "Geography(GeometryZ)"), - ("geography_geometry_zm", "Geography(GeometryZM)"), - ("geography_point", "Geography(Point)"), - ("geography_point_m", "Geography(PointM)"), - ("geography_point_z", "Geography(PointZ)"), - ("geography_point_zm", "Geography(PointZM)"), - ("geography_linestring", "Geography(LineString)"), - ("geography_linestring_m", "Geography(LineStringM)"), - ("geography_linestring_z", "Geography(LineStringZ)"), - ("geography_linestring_zm", "Geography(LineStringZM)"), - ("geography_polygon", "Geography(Polygon)"), - ("geography_polygon_m", "Geography(PolygonM)"), - ("geography_polygon_z", "Geography(PolygonZ)"), - ("geography_polygon_zm", "Geography(PolygonZM)"), - ("geography_multipoint", "Geography(MultiPoint)"), - ("geography_multipoint_m", "Geography(MultiPointM)"), - ("geography_multipoint_z", "Geography(MultiPointZ)"), - ("geography_multipoint_zm", "Geography(MultiPointZM)"), - ("geography_multilinestring", "Geography(MultiLineString)"), - ("geography_multilinestring_m", "Geography(MultiLineStringM)"), - ("geography_multilinestring_z", "Geography(MultiLineStringZ)"), - ("geography_multilinestring_zm", "Geography(MultiLineStringZM)"), - ("geography_multipolygon", "Geography(MultiPolygon)"), - ("geography_multipolygon_m", "Geography(MultiPolygonM)"), - ("geography_multipolygon_z", "Geography(MultiPolygonZ)"), - ("geography_multipolygon_zm", "Geography(MultiPolygonZM)"), - ("geography_geometrycollection", "Geography(GeometryCollection)"), - ("geography_geometrycollection_m", "Geography(GeometryCollectionM)"), - ("geography_geometrycollection_z", "Geography(GeometryCollectionZ)"), - ("geography_geometrycollection_zm", "Geography(GeometryCollectionZM)"), + ("geography_geometry", "Geography(Geometry, 4326)"), + ("geography_geometry_m", "Geography(GeometryM, 4326)"), + ("geography_geometry_z", "Geography(GeometryZ, 4326)"), + ("geography_geometry_zm", "Geography(GeometryZM, 4326)"), + ("geography_point", "Geography(Point, 4326)"), + ("geography_point_m", "Geography(PointM, 4326)"), + ("geography_point_z", "Geography(PointZ, 4326)"), + ("geography_point_zm", "Geography(PointZM, 4326)"), + ("geography_linestring", "Geography(LineString, 4326)"), + ("geography_linestring_m", "Geography(LineStringM, 4326)"), + ("geography_linestring_z", "Geography(LineStringZ, 4326)"), + ("geography_linestring_zm", "Geography(LineStringZM, 4326)"), + ("geography_polygon", "Geography(Polygon, 4326)"), + ("geography_polygon_m", "Geography(PolygonM, 4326)"), + ("geography_polygon_z", "Geography(PolygonZ, 4326)"), + ("geography_polygon_zm", "Geography(PolygonZM, 4326)"), + ("geography_multipoint", "Geography(MultiPoint, 4326)"), + ("geography_multipoint_m", "Geography(MultiPointM, 4326)"), + ("geography_multipoint_z", "Geography(MultiPointZ, 4326)"), + ("geography_multipoint_zm", "Geography(MultiPointZM, 4326)"), + ("geography_multilinestring", "Geography(MultiLineString, 4326)"), + ("geography_multilinestring_m", "Geography(MultiLineStringM, 4326)"), + ("geography_multilinestring_z", "Geography(MultiLineStringZ, 4326)"), + ("geography_multilinestring_zm", "Geography(MultiLineStringZM, 4326)"), + ("geography_multipolygon", "Geography(MultiPolygon, 4326)"), + ("geography_multipolygon_m", "Geography(MultiPolygonM, 4326)"), + ("geography_multipolygon_z", "Geography(MultiPolygonZ, 4326)"), + ("geography_multipolygon_zm", "Geography(MultiPolygonZM, 4326)"), + ("geography_geometrycollection", "Geography(GeometryCollection, 4326)"), + ("geography_geometrycollection_m", "Geography(GeometryCollectionM, 4326)"), + ("geography_geometrycollection_z", "Geography(GeometryCollectionZ, 4326)"), + ("geography_geometrycollection_zm", "Geography(GeometryCollectionZM, 4326)"), ]; const GEOMETRY_EXTRA_TYPES: &[(&str, &str)] = &[ @@ -260,7 +259,7 @@ async fn native_type_spatial_columns_feature_on(api: &mut TestApi) -> TestResult model Spatial { id Int @id geometry Geometry - geometry_geometry Geometry + geometry_srid Geometry @db.Geometry(Geometry, 3857) geometry_geometry_m Geometry @db.Geometry(GeometryM) geometry_geometry_z Geometry @db.Geometry(GeometryZ) geometry_geometry_zm Geometry @db.Geometry(GeometryZM) @@ -292,7 +291,6 @@ async fn native_type_spatial_columns_feature_on(api: &mut TestApi) -> TestResult geometry_geometrycollection_m Geometry @db.Geometry(GeometryCollectionM) geometry_geometrycollection_z Geometry @db.Geometry(GeometryCollectionZ) geometry_geometrycollection_zm Geometry @db.Geometry(GeometryCollectionZM) - geography Geometry @db.Geography(Geometry, 4326) geography_geometry Geometry @db.Geography(Geometry, 4326) geography_geometry_m Geometry @db.Geography(GeometryM, 4326) geography_geometry_z Geometry @db.Geography(GeometryZ, 4326) From 6f2db0fbf6165fcccf3f11c9691eb519870ccb7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A8le=20Nitoref?= Date: Sat, 9 Sep 2023 21:14:07 +0200 Subject: [PATCH 011/103] fix: actually fix geography srid introspection test in postgres dialect --- .../tests/native_types/postgres.rs | 5 ++++- .../sql-schema-describer/src/postgres.rs | 22 ++++++++++--------- 2 files changed, 16 insertions(+), 11 deletions(-) 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 cb99c013f524..4fa9270c35d4 100644 --- a/schema-engine/sql-introspection-tests/tests/native_types/postgres.rs +++ b/schema-engine/sql-introspection-tests/tests/native_types/postgres.rs @@ -101,7 +101,10 @@ const GEOMETRY_TYPES: &[(&str, &str)] = &[ ("geography_geometrycollection", "Geography(GeometryCollection, 4326)"), ("geography_geometrycollection_m", "Geography(GeometryCollectionM, 4326)"), ("geography_geometrycollection_z", "Geography(GeometryCollectionZ, 4326)"), - ("geography_geometrycollection_zm", "Geography(GeometryCollectionZM, 4326)"), + ( + "geography_geometrycollection_zm", + "Geography(GeometryCollectionZM, 4326)", + ), ]; const GEOMETRY_EXTRA_TYPES: &[(&str, &str)] = &[ diff --git a/schema-engine/sql-schema-describer/src/postgres.rs b/schema-engine/sql-schema-describer/src/postgres.rs index 97575a418461..826955a2e715 100644 --- a/schema-engine/sql-schema-describer/src/postgres.rs +++ b/schema-engine/sql-schema-describer/src/postgres.rs @@ -976,7 +976,10 @@ impl<'a> SqlSchemaDescriber<'a> { Ok(()) } - fn get_geometry_info(col: &str) -> Option { + fn get_geometry_info(col: &str, circumstances: &BitFlags) -> Option { + if !circumstances.contains(Circumstances::HasPostGIS) { + return None; + } static GEOM_REGEX: Lazy = Lazy::new(|| Regex::new(r"^(?Pgeometry|geography)(\((?P.+?)(,(?P\d+))?\))?$").unwrap()); GEOM_REGEX.captures(col).and_then(|capture| { @@ -984,7 +987,12 @@ impl<'a> SqlSchemaDescriber<'a> { .name("type") .map(|t| GeometryType::from_str(t.as_str())) .unwrap_or(Ok(GeometryType::default())); - let srid = capture.name("srid").map(|v| v.as_str().parse::()).unwrap_or(Ok(0)); + let is_cockroach = circumstances.contains(Circumstances::Cockroach); + let is_geography = capture.name("class").map(|c| c.as_str() == "geography").unwrap(); + let srid = capture + .name("srid") + .map(|v| v.as_str().parse::()) + .unwrap_or(Ok(if is_geography && !is_cockroach { 4326 } else { 0 })); match (geom_type, srid) { (Ok(ty), Ok(srid)) => Some(GeometryParams { ty, srid }), _ => None, @@ -1572,10 +1580,7 @@ fn get_column_type_postgresql( false => ColumnArity::Nullable, }; - let geometry = match circumstances.contains(Circumstances::HasPostGIS) { - true => SqlSchemaDescriber::get_geometry_info(&formatted_type), - false => None, - }; + let geometry = SqlSchemaDescriber::get_geometry_info(&formatted_type, circumstances); let precision = SqlSchemaDescriber::get_precision(row); let unsupported_type = || (Unsupported(full_data_type.clone()), None); let enum_id: Option<_> = match data_type.as_str() { @@ -1681,10 +1686,7 @@ fn get_column_type_cockroachdb( false => ColumnArity::Nullable, }; - let geometry_type = match circumstances.contains(Circumstances::HasPostGIS) { - true => SqlSchemaDescriber::get_geometry_info(&data_type), - false => None, - }; + let geometry_type = SqlSchemaDescriber::get_geometry_info(&data_type, circumstances); let precision = SqlSchemaDescriber::get_precision(row); let unsupported_type = || (Unsupported(full_data_type.clone()), None); let enum_id: Option<_> = match data_type.as_str() { From a5097ded06d8535fc8c6de899496e7ca95694213 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A8le=20Nitoref?= Date: Sat, 9 Sep 2023 22:52:28 +0200 Subject: [PATCH 012/103] fix: simplify mysql srid introspection on mysql and fixes vitess tests --- .../sql-schema-describer/src/mysql.rs | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/schema-engine/sql-schema-describer/src/mysql.rs b/schema-engine/sql-schema-describer/src/mysql.rs index 3eb54d0e42ad..cd62c2551348 100644 --- a/schema-engine/sql-schema-describer/src/mysql.rs +++ b/schema-engine/sql-schema-describer/src/mysql.rs @@ -369,27 +369,11 @@ impl<'a> SqlSchemaDescriber<'a> { // information schema column names became upper-case in MySQL 8, causing the code fetching // the result values by column name below to fail. let sql_geometry_srid_column = if self.supports_srid_constraints() { - "geom.srs_id" + "srs_id" } else { "NULL" }; - let sql_geometry_information_table = if matches!(flavour, Flavour::MariaDb) { - " - LEFT JOIN information_schema.geometry_columns geom - ON table_schema = geom.g_table_schema - AND table_name = geom.g_table_name - AND column_name = geom.g_geometry_column - " - } else if self.supports_srid_constraints() { - " - LEFT JOIN information_schema.st_geometry_columns geom - USING (table_schema, table_name, column_name) - " - } else { - "" - }; - let sql = format!( " SELECT @@ -407,7 +391,6 @@ impl<'a> SqlSchemaDescriber<'a> { table_name table_name, NULLIF(column_comment, '') AS column_comment FROM information_schema.columns - {sql_geometry_information_table} WHERE table_schema = ? ORDER BY ordinal_position " From 98c913ff9add77a18c5d37432727b12861dda45b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 13 Nov 2023 00:03:01 +0100 Subject: [PATCH 013/103] fix: add missing MySQL version constraint for test requiring support for srid column type constraints --- .../tests/writes/data_types/native_types/mysql.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs index 4c1c80ee7da0..dd3bcee94d98 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs @@ -603,7 +603,7 @@ mod mysql { } // "MySQL native spatial types" should "work" - #[connector_test(schema(schema_geojson_srid_geometry_types))] + #[connector_test(only(MySQL(8)), schema(schema_geojson_srid_geometry_types))] async fn native_geojson_srid_geometry_types(runner: Runner) -> TestResult<()> { insta::assert_snapshot!( run_query!(&runner, r#"mutation { From e287c3844b0e1fbaabcf93c5559e1e63a5083235 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 13 Nov 2023 00:04:14 +0100 Subject: [PATCH 014/103] fix: ignore unsuccessful initialization of SpatiaLite in SQLite query engine test setup --- query-engine/connector-test-kit-rs/qe-setup/src/sqlite.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/query-engine/connector-test-kit-rs/qe-setup/src/sqlite.rs b/query-engine/connector-test-kit-rs/qe-setup/src/sqlite.rs index 37085b191ca7..865c595365c5 100644 --- a/query-engine/connector-test-kit-rs/qe-setup/src/sqlite.rs +++ b/query-engine/connector-test-kit-rs/qe-setup/src/sqlite.rs @@ -6,6 +6,6 @@ pub(crate) async fn sqlite_setup(url: String, source: Datasource, prisma_schema: std::fs::remove_file(source.url.as_literal().unwrap().trim_start_matches("file:")).ok(); let mut connector = sql_schema_connector::SqlSchemaConnector::new_sqlite(); let client = Quaint::new(&url).await.unwrap(); - client.query_raw("SELECT InitSpatialMetaData()", &[]).await.unwrap(); + client.query_raw("SELECT InitSpatialMetaData()", &[]).await.ok(); crate::diff_and_apply(prisma_schema, url, &mut connector).await } From 4e4308c7c760da0e8e7e33c1616d583c269b5f81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 13 Nov 2023 01:54:10 +0100 Subject: [PATCH 015/103] fix: replace intersection test due to MySQL 5.6 quirk --- .../tests/queries/filters/geometry_filter.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs index 5c857f14290e..84f2db907ebb 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs @@ -88,13 +88,13 @@ mod geometry_filter_spec { // geoIntersects insta::assert_snapshot!( - run_query!(&runner, r#"query { findManyTestModel(where: { geom: { geoIntersects: "{\"type\":\"Point\",\"coordinates\":[0, 0]}" }}) { id }}"#), + run_query!(&runner, r#"query { findManyTestModel(where: { geom: { geoIntersects: "{\"type\":\"Polygon\",\"coordinates\":[[[-1,-1],[-1,1],[1,1],[1,-1],[-1,-1]]]}" }}) { id }}"#), @r###"{"data":{"findManyTestModel":[{"id":1}]}}"### ); // Not geoIntersects insta::assert_snapshot!( - run_query!(&runner, r#"query { findManyTestModel(where: { geom: { not: { geoIntersects: "{\"type\":\"Point\",\"coordinates\":[0, 0]}" }}}) { id }}"#), + run_query!(&runner, r#"query { findManyTestModel(where: { geom: { not: { geoIntersects: "{\"type\":\"Polygon\",\"coordinates\":[[[-1,-1],[-1,1],[1,1],[1,-1],[-1,-1]]]}" }}}) { id }}"#), @r###"{"data":{"findManyTestModel":[{"id":2}]}}"### ); From 16f004cc2c4005dfe44a70e99762e779ef928519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Sun, 19 Nov 2023 13:53:17 +0100 Subject: [PATCH 016/103] fix: formatting --- quaint/src/ast/function.rs | 5 +---- quaint/src/ast/values.rs | 3 +-- .../sql-schema-connector/src/sql_renderer/sqlite_renderer.rs | 2 +- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/quaint/src/ast/function.rs b/quaint/src/ast/function.rs index 753ab26e139b..0cb929782415 100644 --- a/quaint/src/ast/function.rs +++ b/quaint/src/ast/function.rs @@ -79,10 +79,7 @@ impl<'a> Function<'a> { } } pub fn returns_geometry(&self) -> bool { - match self.typ_ { - FunctionType::GeomFromText(_) => true, - _ => false, - } + matches!(self.typ_, FunctionType::GeomFromText(_)) } } diff --git a/quaint/src/ast/values.rs b/quaint/src/ast/values.rs index ad1577bed7cd..7ade18091167 100644 --- a/quaint/src/ast/values.rs +++ b/quaint/src/ast/values.rs @@ -56,8 +56,7 @@ impl FromStr for GeometryValue { type Err = String; fn from_str(s: &str) -> Result { - static EWKT_REGEX: Lazy = - Lazy::new(|| Regex::new(r"^(SRID=(?P\d+);)?(?P.+)$").unwrap()); + static EWKT_REGEX: Lazy = Lazy::new(|| Regex::new(r"^(SRID=(?P\d+);)?(?P.+)$").unwrap()); EWKT_REGEX .captures(s) .map(|capture| { diff --git a/schema-engine/connectors/sql-schema-connector/src/sql_renderer/sqlite_renderer.rs b/schema-engine/connectors/sql-schema-connector/src/sql_renderer/sqlite_renderer.rs index 9485a3a7b9b0..695f8c79d604 100644 --- a/schema-engine/connectors/sql-schema-connector/src/sql_renderer/sqlite_renderer.rs +++ b/schema-engine/connectors/sql-schema-connector/src/sql_renderer/sqlite_renderer.rs @@ -10,7 +10,7 @@ use psl::builtin_connectors::SQLiteType; use regex::Regex; use sql_ddl::sqlite as ddl; use sql_schema_describer::{walkers::*, *}; -use std::{fmt::Write, borrow::Cow}; +use std::{borrow::Cow, fmt::Write}; impl SqlRenderer for SqliteFlavour { fn quote<'a>(&self, name: &'a str) -> Quoted<&'a str> { From 71dae2e0a5f196542efa9d381bd0b9aaf0fb54ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Sun, 19 Nov 2023 13:14:57 +0100 Subject: [PATCH 017/103] fix: make Spatialite geometry filters stricter and tighten geometry filter tests --- quaint/src/visitor/sqlite.rs | 20 +++++++++++++++++++ .../tests/queries/filters/geometry_filter.rs | 4 ++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/quaint/src/visitor/sqlite.rs b/quaint/src/visitor/sqlite.rs index 2dfe6b709f8f..3e1ecdc3c8b4 100644 --- a/quaint/src/visitor/sqlite.rs +++ b/quaint/src/visitor/sqlite.rs @@ -281,6 +281,26 @@ impl<'a> Visitor<'a> for Sqlite<'a> { }) } + fn visit_geometry_within(&mut self, left: Expression<'a>, right: Expression<'a>, not: bool) -> visitor::Result { + self.surround_with("ST_Within(", ")", |s| { + s.visit_expression(left)?; + s.write(",")?; + s.visit_expression(right) + })?; + self.write(if not { " != 1" } else { " = 1" })?; + Ok(()) + } + + fn visit_geometry_intersects(&mut self, left: Expression<'a>, right: Expression<'a>, not: bool) -> visitor::Result { + self.surround_with("ST_Intersects(", ")", |s| { + s.visit_expression(left)?; + s.write(",")?; + s.visit_expression(right) + })?; + self.write(if not { " != 1" } else { " = 1" })?; + Ok(()) + } + fn visit_geometry_type_equals( &mut self, left: Expression<'a>, diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs index 84f2db907ebb..d5d549680c85 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs @@ -82,7 +82,7 @@ mod geometry_filter_spec { // Not geoWithin insta::assert_snapshot!( - run_query!(&runner, r#"query { findManyTestModel(where: { geom: { not: { geoWithin: "{\"type\":\"Polygon\",\"coordinates\":[[[1,1],[1,4],[4,4],[4,1],[1,1]]]}" }}}) { id }}"#), + run_query!(&runner, r#"query { findManyTestModel(where: { AND: [{ geom: { not: { geoWithin: "{\"type\":\"Polygon\",\"coordinates\":[[[1,1],[1,4],[4,4],[4,1],[1,1]]]}" }}}, { geom: { not: null }}]}) { id }}"#), @r###"{"data":{"findManyTestModel":[{"id":1}]}}"### ); @@ -94,7 +94,7 @@ mod geometry_filter_spec { // Not geoIntersects insta::assert_snapshot!( - run_query!(&runner, r#"query { findManyTestModel(where: { geom: { not: { geoIntersects: "{\"type\":\"Polygon\",\"coordinates\":[[[-1,-1],[-1,1],[1,1],[1,-1],[-1,-1]]]}" }}}) { id }}"#), + run_query!(&runner, r#"query { findManyTestModel(where: { AND: [{ geom: { not: { geoIntersects: "{\"type\":\"Polygon\",\"coordinates\":[[[-1,-1],[-1,1],[1,1],[1,-1],[-1,-1]]]}" }}}, { geom: { not: null }}]}) { id }}"#), @r###"{"data":{"findManyTestModel":[{"id":2}]}}"### ); From 93f582c691b9a03e3486b81e25b2afe6c39c7429 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Sat, 25 Nov 2023 11:28:32 +0100 Subject: [PATCH 018/103] fix: add SQLite test versions 3 and 3-spatialite, only run query engine geometry tests for spatialite enabled version --- Makefile | 5 +++++ quaint/src/connector/sqlite/native/mod.rs | 8 +++++--- .../tests/queries/filters/geometry_filter.rs | 10 +++++++--- .../order_by_dependent.rs | 2 +- .../writes/data_types/native_types/sqlite.rs | 2 +- .../writes/top_level_mutations/create.rs | 2 +- .../src/connector_tag/mod.rs | 10 +++++++++- .../src/connector_tag/sqlite.rs | 3 +++ .../test-configs/spatialite | 3 +++ .../src/flavour/sqlite.rs | 15 ++++++++++++--- .../src/flavour/sqlite/connection.rs | 8 +++++--- .../src/sql_renderer/sqlite_renderer.rs | 19 +++++++------------ 12 files changed, 59 insertions(+), 28 deletions(-) create mode 100644 query-engine/connector-test-kit-rs/test-configs/spatialite diff --git a/Makefile b/Makefile index 151a58ed4c2b..08737e8de574 100644 --- a/Makefile +++ b/Makefile @@ -87,6 +87,11 @@ start-sqlite: dev-sqlite: cp $(CONFIG_PATH)/sqlite $(CONFIG_FILE) +start-spatialite: + +dev-spatialite: + cp $(CONFIG_PATH)/spatialite $(CONFIG_FILE) + dev-libsql-js: build-qe-napi build-connector-kit-js cp $(CONFIG_PATH)/libsql-js $(CONFIG_FILE) diff --git a/quaint/src/connector/sqlite/native/mod.rs b/quaint/src/connector/sqlite/native/mod.rs index 9220fe75b517..5d2a6a5ef2b5 100644 --- a/quaint/src/connector/sqlite/native/mod.rs +++ b/quaint/src/connector/sqlite/native/mod.rs @@ -32,9 +32,11 @@ fn load_spatialite(conn: &rusqlite::Connection) -> crate::Result<()> { // Loading Spatialite here isn't ideal, but needed because it has to be // done for every new pooled connection..? if let Ok(spatialite_path) = std::env::var("SPATIALITE_PATH") { - unsafe { - let _guard = LoadExtensionGuard::new(conn)?; - conn.load_extension(spatialite_path, None)?; + if !spatialite_path.is_empty() { + unsafe { + let _guard = LoadExtensionGuard::new(conn)?; + conn.load_extension(spatialite_path, None)?; + } } } Ok(()) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs index d5d549680c85..3fc5c3d7a797 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs @@ -101,17 +101,21 @@ mod geometry_filter_spec { Ok(()) } - #[connector_test(schema(schema), exclude(Postgres))] + #[connector_test(schema(schema), exclude(Postgres, Sqlite(3, "libsql.js")))] async fn basic_where(runner: Runner) -> TestResult<()> { basic_where_test(runner).await } - #[connector_test(schema(schema), exclude(Postgres))] + #[connector_test(schema(schema), exclude(Postgres, Sqlite(3, "libsql.js")))] async fn where_shorthands(runner: Runner) -> TestResult<()> { where_shorthands_test(runner).await } - #[connector_test(schema(schema), exclude(Postgres), capabilities(GeometryFiltering))] + #[connector_test( + schema(schema), + exclude(Postgres, Sqlite(3, "libsql.js")), + capabilities(GeometryFiltering) + )] async fn geometric_comparison_filters(runner: Runner) -> TestResult<()> { geometric_comparison_filters_test(runner).await } diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/order_and_pagination/order_by_dependent.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/order_and_pagination/order_by_dependent.rs index b4c6e7b5ef34..2194d7842a04 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/order_and_pagination/order_by_dependent.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/order_and_pagination/order_by_dependent.rs @@ -275,7 +275,7 @@ mod order_by_dependent { } } }"#, - MongoDb(_) | Sqlite(_)=> vec![r#"{"data":{"findManyModelA":[{"id":2,"b":{"c":{"a":{"id":4}}}},{"id":1,"b":{"c":{"a":{"id":3}}}},{"id":3,"b":null},{"id":4,"b":null}]}}"#], + MongoDb(_) | Sqlite(_) => vec![r#"{"data":{"findManyModelA":[{"id":2,"b":{"c":{"a":{"id":4}}}},{"id":1,"b":{"c":{"a":{"id":3}}}},{"id":3,"b":null},{"id":4,"b":null}]}}"#], MySql(_) | CockroachDb(_) => vec![ r#"{"data":{"findManyModelA":[{"id":2,"b":{"c":{"a":{"id":4}}}},{"id":1,"b":{"c":{"a":{"id":3}}}},{"id":4,"b":null},{"id":3,"b":null}]}}"#, r#"{"data":{"findManyModelA":[{"id":2,"b":{"c":{"a":{"id":4}}}},{"id":1,"b":{"c":{"a":{"id":3}}}},{"id":3,"b":null},{"id":4,"b":null}]}}"#, diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sqlite.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sqlite.rs index 10fd173a7c99..338278c9166f 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sqlite.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sqlite.rs @@ -1,6 +1,6 @@ use query_engine_tests::*; -#[test_suite(only(Sqlite))] +#[test_suite(only(Sqlite("3-spatialite")))] mod sqlite { use indoc::indoc; use query_engine_tests::run_query; diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs index 1e46dc4adafe..b018a10d46c4 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs @@ -475,7 +475,7 @@ mod geometry_create { schema.to_owned() } - #[connector_test(schema(geometry_opt), exclude(Postgres))] + #[connector_test(schema(geometry_opt), exclude(Postgres, Sqlite(3, "libsql.js")))] async fn create_geometry(runner: Runner) -> TestResult<()> { create_geometry_test(runner).await } diff --git a/query-engine/connector-test-kit-rs/query-tests-setup/src/connector_tag/mod.rs b/query-engine/connector-test-kit-rs/query-tests-setup/src/connector_tag/mod.rs index a3b84a9173a8..f3e3fde9b4e2 100644 --- a/query-engine/connector-test-kit-rs/query-tests-setup/src/connector_tag/mod.rs +++ b/query-engine/connector-test-kit-rs/query-tests-setup/src/connector_tag/mod.rs @@ -169,12 +169,20 @@ pub(crate) fn connection_string( } None => unreachable!("A versioned connector must have a concrete version to run."), }, - ConnectorVersion::Sqlite(_) => { + ConnectorVersion::Sqlite(version) => { let workspace_root = std::env::var("WORKSPACE_ROOT") .unwrap_or_else(|_| ".".to_owned()) .trim_end_matches('/') .to_owned(); + let spatialite_path = std::env::var("SPATIALITE_PATH"); + match (version, spatialite_path) { + (Some(SqliteVersion::V3Spatialite), Err(_)) => { + panic!("SPATIALITE_PATH env var should be set for version 3-spatialite") + } + (None, _) => unreachable!("A versioned connector must have a concrete version to run."), + (_, _) => (), + }; format!("file://{workspace_root}/db/{database}.db") } ConnectorVersion::CockroachDb(v) => { diff --git a/query-engine/connector-test-kit-rs/query-tests-setup/src/connector_tag/sqlite.rs b/query-engine/connector-test-kit-rs/query-tests-setup/src/connector_tag/sqlite.rs index 5f4dab56784a..d88c9443abb2 100644 --- a/query-engine/connector-test-kit-rs/query-tests-setup/src/connector_tag/sqlite.rs +++ b/query-engine/connector-test-kit-rs/query-tests-setup/src/connector_tag/sqlite.rs @@ -29,6 +29,7 @@ impl ConnectorTagInterface for SqliteConnectorTag { #[derive(Clone, Debug, PartialEq, Eq)] pub enum SqliteVersion { V3, + V3Spatialite, LibsqlJS, } @@ -36,6 +37,7 @@ impl ToString for SqliteVersion { fn to_string(&self) -> String { match self { SqliteVersion::V3 => "3".to_string(), + SqliteVersion::V3Spatialite => "3-spatialite".to_string(), SqliteVersion::LibsqlJS => "libsql.js".to_string(), } } @@ -47,6 +49,7 @@ impl TryFrom<&str> for SqliteVersion { fn try_from(s: &str) -> Result { let version = match s { "3" => Self::V3, + "3-spatialite" => Self::V3Spatialite, "libsql.js" => Self::LibsqlJS, _ => return Err(TestError::parse_error(format!("Unknown SQLite version `{s}`"))), }; diff --git a/query-engine/connector-test-kit-rs/test-configs/spatialite b/query-engine/connector-test-kit-rs/test-configs/spatialite new file mode 100644 index 000000000000..b76e95b1bee0 --- /dev/null +++ b/query-engine/connector-test-kit-rs/test-configs/spatialite @@ -0,0 +1,3 @@ +{ + "connector": "sqlite", + "version": "3-spatialite"} diff --git a/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite.rs b/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite.rs index 2c6ca751c854..4e963e4d5f78 100644 --- a/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite.rs +++ b/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite.rs @@ -22,9 +22,18 @@ pub(crate) struct SqliteFlavour { impl SqliteFlavour { pub(crate) fn has_spatialite(&self) -> bool { - // TODO@geometry: FIXME! how can we set this at instanciation ? - // currently set to false to avoid too many failing tests - false + // TODO@geometry: How can we set this more safely at instanciation ? + // Ideally, we'd want to check if the library can be loaded successfully + // e.g. by checking if `SELECT spatialite_version()` returns something. + // But we might also want to check if a database has had tables and triggers + // created by spatialite even though the user doesn't set SPATIALITE_PATH + // because operations not taking those into account might results in a + // invalid database state (not tested) + if let Ok(spatialite_path) = std::env::var("SPATIALITE_PATH") { + !spatialite_path.is_empty() + } else { + false + } } } diff --git a/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite/connection.rs b/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite/connection.rs index bf43f1446f2a..aa98e95cf45f 100644 --- a/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite/connection.rs +++ b/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite/connection.rs @@ -13,9 +13,11 @@ pub(super) struct Connection(Mutex); fn load_spatialite(conn: &rusqlite::Connection) { // TODO@geometry: raise an appropriate error when spatialite cannot be loaded instead if let Ok(spatialite_path) = std::env::var("SPATIALITE_PATH") { - unsafe { - let _guard = LoadExtensionGuard::new(conn).unwrap(); - conn.load_extension(spatialite_path, None).unwrap(); + if !spatialite_path.is_empty() { + unsafe { + let _guard = LoadExtensionGuard::new(conn).unwrap(); + conn.load_extension(spatialite_path, None).unwrap(); + } } } } diff --git a/schema-engine/connectors/sql-schema-connector/src/sql_renderer/sqlite_renderer.rs b/schema-engine/connectors/sql-schema-connector/src/sql_renderer/sqlite_renderer.rs index 695f8c79d604..0bff2f6b6547 100644 --- a/schema-engine/connectors/sql-schema-connector/src/sql_renderer/sqlite_renderer.rs +++ b/schema-engine/connectors/sql-schema-connector/src/sql_renderer/sqlite_renderer.rs @@ -142,11 +142,15 @@ impl SqlRenderer for SqliteFlavour { .map(|c| c.map(|c| c.name().into()).collect()); } - let create_geometries = &self.render_create_geometry_columns(table, table_name); + let create_geometries = if self.has_spatialite() { + self.render_create_geometry_columns(table, table_name) + } else { + "".to_string() + }; if create_geometries.is_empty() { create_table.to_string() } else { - create_table.to_string() + "\n;" + create_geometries + create_table.to_string() + "\n;" + &create_geometries } } @@ -233,19 +237,10 @@ impl SqlRenderer for SqliteFlavour { if self.has_spatialite() { result.push(format!("SELECT DropTable(NULL, '{}')", tables.previous.name())); - result.push(format!( - "SELECT RenameTable('{old_name}', '{new_name}')", - old_name = temporary_table_name, - new_name = tables.next.name(), - )); } else { result.push(format!(r#"DROP TABLE "{}""#, tables.previous.name())); - result.push(format!( - r#"ALTER TABLE "{old_name}" RENAME TO "{new_name}""#, - old_name = temporary_table_name, - new_name = tables.next.name(), - )); } + result.push(self.render_rename_table(None, &temporary_table_name, tables.next.name())); for index in tables.next.indexes().filter(|idx| !idx.is_primary_key()) { result.push(self.render_create_index(index)); From 6cd70be4f4be6b0dd48de240ecd50bff7e5e0050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Fri, 24 Nov 2023 10:12:08 +0100 Subject: [PATCH 019/103] chore: add Spatialite tests to CI --- .github/workflows/test-query-engine.yml | 10 ++++++++++ .github/workflows/test-schema-engine.yml | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/.github/workflows/test-query-engine.yml b/.github/workflows/test-query-engine.yml index b86fcbbbab0c..03da84f114a9 100644 --- a/.github/workflows/test-query-engine.yml +++ b/.github/workflows/test-query-engine.yml @@ -45,6 +45,10 @@ jobs: single_threaded: false connector: 'sqlite' version: '3' + - name: 'spatialite' + single_threaded: false + connector: 'sqlite' + version: '3-spatialite' - name: 'mongodb_4_2' single_threaded: true connector: 'mongodb' @@ -113,12 +117,18 @@ jobs: - uses: dtolnay/rust-toolchain@stable + - name: Install Spatialite + if: ${{ matrix.database.name == 'spatialite' }} + run: apt install -y libsqlite3-mod-spatialite + - run: export WORKSPACE_ROOT=$(pwd) && cargo test --package query-engine-tests -- --test-threads=1 if: ${{ matrix.database.single_threaded }} env: CLICOLOR_FORCE: 1 + SPATIALITE_PATH: ${{ matrix.database.name == 'spatialite' && 'mod_spatialite' || null }} - run: export WORKSPACE_ROOT=$(pwd) && cargo test --package query-engine-tests -- --test-threads=8 if: ${{ !matrix.database.single_threaded }} env: CLICOLOR_FORCE: 1 + SPATIALITE_PATH: ${{ matrix.database.name == 'spatialite' && 'mod_spatialite' || null }} diff --git a/.github/workflows/test-schema-engine.yml b/.github/workflows/test-schema-engine.yml index 6b392f373ba6..c359abbdb187 100644 --- a/.github/workflows/test-schema-engine.yml +++ b/.github/workflows/test-schema-engine.yml @@ -96,6 +96,8 @@ jobs: url: 'postgresql://prisma@localhost:26257' - name: sqlite url: sqlite + - name: spatialite + url: sqlite - name: vitess_8_0 url: 'mysql://root:prisma@localhost:33807/test' shadow_database_url: 'mysql://root:prisma@localhost:33808/shadow' @@ -118,6 +120,10 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Install Spatialite + if: ${{ matrix.database.name == 'spatialite' }} + run: sudo apt install -y libsqlite3-mod-spatialite + - name: 'Start ${{ matrix.database.name }}' run: make start-${{ matrix.database.name }} @@ -126,18 +132,21 @@ jobs: env: CLICOLOR_FORCE: 1 TEST_DATABASE_URL: ${{ matrix.database.url }} + SPATIALITE_PATH: ${{ matrix.database.name == 'spatialite' && 'mod_spatialite' || null }} - run: cargo test -p sql-schema-describer if: ${{ !matrix.database.single_threaded }} env: CLICOLOR_FORCE: 1 TEST_DATABASE_URL: ${{ matrix.database.url }} + SPATIALITE_PATH: ${{ matrix.database.name == 'spatialite' && 'mod_spatialite' || null }} - run: cargo test -p sql-migration-tests if: ${{ !matrix.database.single_threaded }} env: CLICOLOR_FORCE: 1 TEST_DATABASE_URL: ${{ matrix.database.url }} + SPATIALITE_PATH: ${{ matrix.database.name == 'spatialite' && 'mod_spatialite' || null }} RUST_LOG: debug - run: cargo test -p schema-engine-cli @@ -145,6 +154,7 @@ jobs: env: CLICOLOR_FORCE: 1 TEST_DATABASE_URL: ${{ matrix.database.url }} + SPATIALITE_PATH: ${{ matrix.database.name == 'spatialite' && 'mod_spatialite' || null }} - run: cargo test -p sql-introspection-tests -- --test-threads=1 if: ${{ matrix.database.is_vitess }} From e6185beeee5fa069b9cbd549efe0e270d5dfb1bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Sun, 26 Nov 2023 22:53:41 +0100 Subject: [PATCH 020/103] fix: incorrect dependency order --- query-engine/connectors/sql-query-connector/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/query-engine/connectors/sql-query-connector/Cargo.toml b/query-engine/connectors/sql-query-connector/Cargo.toml index c3a84ed28a2d..41b55fa5fc0e 100644 --- a/query-engine/connectors/sql-query-connector/Cargo.toml +++ b/query-engine/connectors/sql-query-connector/Cargo.toml @@ -27,11 +27,11 @@ uuid.workspace = true opentelemetry = { version = "0.17", features = ["tokio"] } tracing-opentelemetry = "0.17.3" cuid = { git = "https://github.com/prisma/cuid-rust", branch = "wasm32-support" } +regex = "1.9.3" +geozero = "0.10.0" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] quaint.workspace = true -regex = "1.9.3" -geozero = "0.10.0" [target.'cfg(target_arch = "wasm32")'.dependencies] quaint = { path = "../../../quaint" } From 42e591422311df8c4d58f69a65ebb38a5d01a097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Sun, 26 Nov 2023 22:54:09 +0100 Subject: [PATCH 021/103] fix: add missing Spatialite system table to the list --- .../src/sql_schema_differ/sql_schema_differ_flavour/sqlite.rs | 1 + schema-engine/sql-schema-describer/src/sqlite.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/schema-engine/connectors/sql-schema-connector/src/sql_schema_differ/sql_schema_differ_flavour/sqlite.rs b/schema-engine/connectors/sql-schema-connector/src/sql_schema_differ/sql_schema_differ_flavour/sqlite.rs index a964512c63b8..11417ae7a3aa 100644 --- a/schema-engine/connectors/sql-schema-connector/src/sql_schema_differ/sql_schema_differ_flavour/sqlite.rs +++ b/schema-engine/connectors/sql-schema-connector/src/sql_schema_differ/sql_schema_differ_flavour/sqlite.rs @@ -25,6 +25,7 @@ static SPATIALITE_TABLES_OR_VIEWS: Lazy = Lazy::new(|| { "(?i)^iso_metadata$", "(?i)^iso_metadata_reference$", "(?i)^iso_metadata_view$", + "(?i)^knn$", "(?i)^knn2$", "(?i)^networks$", "(?i)^raster_coverages$", diff --git a/schema-engine/sql-schema-describer/src/sqlite.rs b/schema-engine/sql-schema-describer/src/sqlite.rs index 0d23b748c22e..c7f74ab71bc9 100644 --- a/schema-engine/sql-schema-describer/src/sqlite.rs +++ b/schema-engine/sql-schema-describer/src/sqlite.rs @@ -705,6 +705,7 @@ static SPATIALITE_SYSTEM_TABLES: Lazy = Lazy::new(|| { "(?i)^iso_metadata$", "(?i)^iso_metadata_reference$", "(?i)^iso_metadata_view$", + "(?i)^knn$", "(?i)^knn2$", "(?i)^networks$", "(?i)^raster_coverages$", From e1da2f78add1a5bd58cc75ec3aff0b75d54877d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Sun, 26 Nov 2023 23:13:27 +0100 Subject: [PATCH 022/103] fix: null_geometry return value --- quaint/src/ast/values.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quaint/src/ast/values.rs b/quaint/src/ast/values.rs index 7ade18091167..f2185b8d6c42 100644 --- a/quaint/src/ast/values.rs +++ b/quaint/src/ast/values.rs @@ -529,7 +529,7 @@ impl<'a> Value<'a> { } pub fn null_geometry() -> Self { - ValueType::Time(None).into() + ValueType::Geometry(None).into() } } From 5a255ac6ce686c5a03b5a657474fe1041eb3b535 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Tue, 28 Nov 2023 03:14:51 +0100 Subject: [PATCH 023/103] refactor: share SQLITE_SYSTEM_TABLES with sql-schema-connector --- .../sql_schema_differ_flavour/sqlite.rs | 81 +-------- .../sql-schema-describer/src/sqlite.rs | 156 +++++++++--------- 2 files changed, 78 insertions(+), 159 deletions(-) diff --git a/schema-engine/connectors/sql-schema-connector/src/sql_schema_differ/sql_schema_differ_flavour/sqlite.rs b/schema-engine/connectors/sql-schema-connector/src/sql_schema_differ/sql_schema_differ_flavour/sqlite.rs index 11417ae7a3aa..d42ef3ad8b2e 100644 --- a/schema-engine/connectors/sql-schema-connector/src/sql_schema_differ/sql_schema_differ_flavour/sqlite.rs +++ b/schema-engine/connectors/sql-schema-connector/src/sql_schema_differ/sql_schema_differ_flavour/sqlite.rs @@ -3,83 +3,8 @@ use crate::{ flavour::SqliteFlavour, migration_pair::MigrationPair, sql_schema_differ::column::ColumnTypeChange, sql_schema_differ::differ_database::DifferDatabase, }; -use once_cell::sync::Lazy; -use regex::RegexSet; -use sql_schema_describer::{walkers::TableColumnWalker, ColumnTypeFamily}; -/// These can be tables or views, depending on the PostGIS version. In both cases, they should be ignored. -static SPATIALITE_TABLES_OR_VIEWS: Lazy = Lazy::new(|| { - RegexSet::new([ - "(?i)^data_licenses$", - "(?i)^elementarygeometries$", - "(?i)^geometry_columns$", - "(?i)^geometry_columns_auth$", - "(?i)^geometry_columns_field_infos$", - "(?i)^geometry_columns_statistics$", - "(?i)^geometry_columns_time$", - "(?i)^geom_cols_ref_sys$", - "(?i)^idx_iso_metadata_geometry$", - "(?i)^idx_iso_metadata_geometry_node$", - "(?i)^idx_iso_metadata_geometry_parent$", - "(?i)^idx_iso_metadata_geometry_rowid$", - "(?i)^iso_metadata$", - "(?i)^iso_metadata_reference$", - "(?i)^iso_metadata_view$", - "(?i)^knn$", - "(?i)^knn2$", - "(?i)^networks$", - "(?i)^raster_coverages$", - "(?i)^raster_coverages_keyword$", - "(?i)^raster_coverages_ref_sys$", - "(?i)^raster_coverages_srid$", - "(?i)^rl2map_configurations$", - "(?i)^rl2map_configurations_view$", - "(?i)^se_external_graphics$", - "(?i)^se_external_graphics_view$", - "(?i)^se_fonts$", - "(?i)^se_fonts_view$", - "(?i)^se_raster_styled_layers$", - "(?i)^se_raster_styled_layers_view$", - "(?i)^se_raster_styles$", - "(?i)^se_raster_styles_view$", - "(?i)^se_vector_styled_layers$", - "(?i)^se_vector_styled_layers_view$", - "(?i)^se_vector_styles$", - "(?i)^se_vector_styles_view$", - "(?i)^spatialindex$", - "(?i)^spatialite_history$", - "(?i)^spatial_ref_sys$", - "(?i)^spatial_ref_sys_all$", - "(?i)^spatial_ref_sys_aux$", - "(?i)^sql_statements_log$", - "(?i)^stored_procedures$", - "(?i)^stored_variables$", - "(?i)^topologies$", - "(?i)^vector_coverages$", - "(?i)^vector_coverages_keyword$", - "(?i)^vector_coverages_ref_sys$", - "(?i)^vector_coverages_srid$", - "(?i)^vector_layers$", - "(?i)^vector_layers_auth$", - "(?i)^vector_layers_field_infos$", - "(?i)^vector_layers_statistics$", - "(?i)^views_geometry_columns$", - "(?i)^views_geometry_columns_auth$", - "(?i)^views_geometry_columns_field_infos$", - "(?i)^views_geometry_columns_statistics$", - "(?i)^virts_geometry_collection$", - "(?i)^virts_geometry_collectionm$", - "(?i)^virts_geometry_columns$", - "(?i)^virts_geometry_columns_auth$", - "(?i)^virts_geometry_columns_field_infos$", - "(?i)^virts_geometry_columns_statistics$", - "(?i)^wms_getcapabilities$", - "(?i)^wms_getmap$", - "(?i)^wms_ref_sys$", - "(?i)^wms_settings$", - ]) - .unwrap() -}); +use sql_schema_describer::{sqlite::SQLITE_SYSTEM_TABLES, walkers::TableColumnWalker, ColumnTypeFamily}; impl SqlSchemaDifferFlavour for SqliteFlavour { fn can_rename_foreign_key(&self) -> bool { @@ -140,10 +65,10 @@ impl SqlSchemaDifferFlavour for SqliteFlavour { } fn table_should_be_ignored(&self, table_name: &str) -> bool { - SPATIALITE_TABLES_OR_VIEWS.is_match(table_name) + SQLITE_SYSTEM_TABLES.is_match(table_name) } fn view_should_be_ignored(&self, view_name: &str) -> bool { - SPATIALITE_TABLES_OR_VIEWS.is_match(view_name) + SQLITE_SYSTEM_TABLES.is_match(view_name) } } diff --git a/schema-engine/sql-schema-describer/src/sqlite.rs b/schema-engine/sql-schema-describer/src/sqlite.rs index c7f74ab71bc9..8804e864f507 100644 --- a/schema-engine/sql-schema-describer/src/sqlite.rs +++ b/schema-engine/sql-schema-describer/src/sqlite.rs @@ -672,91 +672,85 @@ fn unquote_sqlite_string_default(s: &str) -> Cow<'_, str> { /// Returns whether a table is one of the SQLite system tables. fn is_system_table(table_name: &str) -> bool { - SQLITE_SYSTEM_TABLES - .iter() - .any(|system_table| table_name == *system_table) - || SPATIALITE_SYSTEM_TABLES.is_match(table_name) + SQLITE_SYSTEM_TABLES.is_match(table_name) } /// See https://www.sqlite.org/fileformat2.html -const SQLITE_SYSTEM_TABLES: &[&str] = &[ - "sqlite_sequence", - "sqlite_stat1", - "sqlite_stat2", - "sqlite_stat3", - "sqlite_stat4", -]; - -/// These can be tables or views, depending on the Spatialite version. In both cases, they should be ignored. -static SPATIALITE_SYSTEM_TABLES: Lazy = Lazy::new(|| { +pub static SQLITE_SYSTEM_TABLES: Lazy = Lazy::new(|| { RegexSet::new([ - "(?i)^data_licenses$", - "(?i)^elementarygeometries$", - "(?i)^geometry_columns$", - "(?i)^geometry_columns_auth$", - "(?i)^geometry_columns_field_infos$", - "(?i)^geometry_columns_statistics$", - "(?i)^geometry_columns_time$", - "(?i)^geom_cols_ref_sys$", - "(?i)^idx_iso_metadata_geometry$", - "(?i)^idx_iso_metadata_geometry_node$", - "(?i)^idx_iso_metadata_geometry_parent$", - "(?i)^idx_iso_metadata_geometry_rowid$", - "(?i)^iso_metadata$", - "(?i)^iso_metadata_reference$", - "(?i)^iso_metadata_view$", - "(?i)^knn$", - "(?i)^knn2$", - "(?i)^networks$", - "(?i)^raster_coverages$", - "(?i)^raster_coverages_keyword$", - "(?i)^raster_coverages_ref_sys$", - "(?i)^raster_coverages_srid$", - "(?i)^rl2map_configurations$", - "(?i)^rl2map_configurations_view$", - "(?i)^se_external_graphics$", - "(?i)^se_external_graphics_view$", - "(?i)^se_fonts$", - "(?i)^se_fonts_view$", - "(?i)^se_raster_styled_layers$", - "(?i)^se_raster_styled_layers_view$", - "(?i)^se_raster_styles$", - "(?i)^se_raster_styles_view$", - "(?i)^se_vector_styled_layers$", - "(?i)^se_vector_styled_layers_view$", - "(?i)^se_vector_styles$", - "(?i)^se_vector_styles_view$", - "(?i)^spatialindex$", - "(?i)^spatialite_history$", - "(?i)^spatial_ref_sys$", - "(?i)^spatial_ref_sys_all$", - "(?i)^spatial_ref_sys_aux$", - "(?i)^sql_statements_log$", - "(?i)^stored_procedures$", - "(?i)^stored_variables$", - "(?i)^topologies$", - "(?i)^vector_coverages$", - "(?i)^vector_coverages_keyword$", - "(?i)^vector_coverages_ref_sys$", - "(?i)^vector_coverages_srid$", - "(?i)^vector_layers$", - "(?i)^vector_layers_auth$", - "(?i)^vector_layers_field_infos$", - "(?i)^vector_layers_statistics$", - "(?i)^views_geometry_columns$", - "(?i)^views_geometry_columns_auth$", - "(?i)^views_geometry_columns_field_infos$", - "(?i)^views_geometry_columns_statistics$", - "(?i)^virts_geometry_collection$", - "(?i)^virts_geometry_collectionm$", - "(?i)^virts_geometry_columns$", - "(?i)^virts_geometry_columns_auth$", - "(?i)^virts_geometry_columns_field_infos$", - "(?i)^virts_geometry_columns_statistics$", - "(?i)^wms_getcapabilities$", - "(?i)^wms_getmap$", - "(?i)^wms_ref_sys$", - "(?i)^wms_settings$", + "^sqlite_sequence$", + "^sqlite_stat1$", + "^sqlite_stat2$", + "^sqlite_stat3$", + "^sqlite_stat4$", + "^data_licenses$", + // Spatialite generated table and views + "^ElementaryGeometries$", + "^geometry_columns$", + "^geometry_columns_auth$", + "^geometry_columns_field_infos$", + "^geometry_columns_statistics$", + "^geometry_columns_time$", + "^geom_cols_ref_sys$", + "^idx_ISO_metadata_geometry$", + "^idx_ISO_metadata_geometry_node$", + "^idx_ISO_metadata_geometry_parent$", + "^idx_ISO_metadata_geometry_rowid$", + "^ISO_metadata$", + "^ISO_metadata_reference$", + "^ISO_metadata_view$", + "^KNN$", + "^KNN2$", + "^networks$", + "^raster_coverages$", + "^raster_coverages_keyword$", + "^raster_coverages_ref_sys$", + "^raster_coverages_srid$", + "^rl2map_configurations$", + "^rl2map_configurations_view$", + "^SE_external_graphics$", + "^SE_external_graphics_view$", + "^SE_fonts$", + "^SE_fonts_view$", + "^SE_raster_styled_layers$", + "^SE_raster_styled_layers_view$", + "^SE_raster_styles$", + "^SE_raster_styles_view$", + "^SE_vector_styled_layers$", + "^SE_vector_styled_layers_view$", + "^SE_vector_styles$", + "^SE_vector_styles_view$", + "^SpatialIndex$", + "^spatialite_history$", + "^spatial_ref_sys$", + "^spatial_ref_sys_all$", + "^spatial_ref_sys_aux$", + "^sql_statements_log$", + "^stored_procedures$", + "^stored_variables$", + "^topologies$", + "^vector_coverages$", + "^vector_coverages_keyword$", + "^vector_coverages_ref_sys$", + "^vector_coverages_srid$", + "^vector_layers$", + "^vector_layers_auth$", + "^vector_layers_field_infos$", + "^vector_layers_statistics$", + "^views_geometry_columns$", + "^views_geometry_columns_auth$", + "^views_geometry_columns_field_infos$", + "^views_geometry_columns_statistics$", + "^virts_geometry_collection$", + "^virts_geometry_collectionm$", + "^virts_geometry_columns$", + "^virts_geometry_columns_auth$", + "^virts_geometry_columns_field_infos$", + "^virts_geometry_columns_statistics$", + "^wms_getcapabilities$", + "^wms_getmap$", + "^wms_ref_sys$", + "^wms_settings$", ]) .unwrap() }); From 1290ef7ef5cc0508f4784f6090090fa9519ba6e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Tue, 28 Nov 2023 03:54:34 +0100 Subject: [PATCH 024/103] refactor: execute InitSpatialMetaData in quaint --- quaint/src/connector/sqlite/native/mod.rs | 3 ++- .../qe-setup/src/sqlite.rs | 3 --- .../src/flavour/sqlite/connection.rs | 18 +++--------------- .../tests/native_types/sqlite.rs | 2 -- .../tests/describers/sqlite_describer_tests.rs | 2 -- 5 files changed, 5 insertions(+), 23 deletions(-) diff --git a/quaint/src/connector/sqlite/native/mod.rs b/quaint/src/connector/sqlite/native/mod.rs index 5d2a6a5ef2b5..4dc8a7d056c1 100644 --- a/quaint/src/connector/sqlite/native/mod.rs +++ b/quaint/src/connector/sqlite/native/mod.rs @@ -28,7 +28,7 @@ pub struct Sqlite { pub(crate) client: Mutex, } -fn load_spatialite(conn: &rusqlite::Connection) -> crate::Result<()> { +pub fn load_spatialite(conn: &rusqlite::Connection) -> crate::Result<()> { // Loading Spatialite here isn't ideal, but needed because it has to be // done for every new pooled connection..? if let Ok(spatialite_path) = std::env::var("SPATIALITE_PATH") { @@ -36,6 +36,7 @@ fn load_spatialite(conn: &rusqlite::Connection) -> crate::Result<()> { unsafe { let _guard = LoadExtensionGuard::new(conn)?; conn.load_extension(spatialite_path, None)?; + conn.query_row("SELECT InitSpatialMetaData(1)", [], |_| Ok(())).unwrap(); } } } diff --git a/query-engine/connector-test-kit-rs/qe-setup/src/sqlite.rs b/query-engine/connector-test-kit-rs/qe-setup/src/sqlite.rs index 865c595365c5..da9c93d46bc8 100644 --- a/query-engine/connector-test-kit-rs/qe-setup/src/sqlite.rs +++ b/query-engine/connector-test-kit-rs/qe-setup/src/sqlite.rs @@ -1,11 +1,8 @@ use psl::Datasource; -use quaint::{prelude::*, single::Quaint}; use schema_core::schema_connector::ConnectorResult; pub(crate) async fn sqlite_setup(url: String, source: Datasource, prisma_schema: &str) -> ConnectorResult<()> { std::fs::remove_file(source.url.as_literal().unwrap().trim_start_matches("file:")).ok(); let mut connector = sql_schema_connector::SqlSchemaConnector::new_sqlite(); - let client = Quaint::new(&url).await.unwrap(); - client.query_raw("SELECT InitSpatialMetaData()", &[]).await.ok(); crate::diff_and_apply(prisma_schema, url, &mut connector).await } diff --git a/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite/connection.rs b/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite/connection.rs index aa98e95cf45f..47ed9ceed103 100644 --- a/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite/connection.rs +++ b/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite/connection.rs @@ -2,7 +2,7 @@ pub(crate) use quaint::connector::rusqlite; -use quaint::connector::{rusqlite::LoadExtensionGuard, GetRow, ToColumnNames}; +use quaint::connector::{GetRow, ToColumnNames, load_spatialite}; use schema_connector::{ConnectorError, ConnectorResult}; use sql_schema_describer::{sqlite as describer, DescriberErrorKind, SqlSchema}; use std::sync::Mutex; @@ -10,28 +10,16 @@ use user_facing_errors::schema_engine::ApplyMigrationError; pub(super) struct Connection(Mutex); -fn load_spatialite(conn: &rusqlite::Connection) { - // TODO@geometry: raise an appropriate error when spatialite cannot be loaded instead - if let Ok(spatialite_path) = std::env::var("SPATIALITE_PATH") { - if !spatialite_path.is_empty() { - unsafe { - let _guard = LoadExtensionGuard::new(conn).unwrap(); - conn.load_extension(spatialite_path, None).unwrap(); - } - } - } -} - impl Connection { pub(super) fn new(params: &super::Params) -> ConnectorResult { let conn = rusqlite::Connection::open(¶ms.file_path).map_err(convert_error)?; - load_spatialite(&conn); + load_spatialite(&conn).unwrap(); Ok(Connection(Mutex::new(conn))) } pub(super) fn new_in_memory() -> Self { let conn = rusqlite::Connection::open_in_memory().unwrap(); - load_spatialite(&conn); + load_spatialite(&conn).unwrap(); Connection(Mutex::new(conn)) } diff --git a/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs b/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs index 6226ae2957ea..0309a16f3aeb 100644 --- a/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs +++ b/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs @@ -4,8 +4,6 @@ use sql_introspection_tests::test_api::*; #[test_connector(tags(Spatialite))] async fn native_spatial_type_columns_feature_on(api: &mut TestApi) -> TestResult { let setup = indoc! {r#" - SELECT InitSpatialMetaData(); - CREATE TABLE "User" ( id INTEGER PRIMARY KEY ); diff --git a/schema-engine/sql-schema-describer/tests/describers/sqlite_describer_tests.rs b/schema-engine/sql-schema-describer/tests/describers/sqlite_describer_tests.rs index 7528742f95dd..f75d7df8803c 100644 --- a/schema-engine/sql-schema-describer/tests/describers/sqlite_describer_tests.rs +++ b/schema-engine/sql-schema-describer/tests/describers/sqlite_describer_tests.rs @@ -214,8 +214,6 @@ fn sqlite_column_types_must_work(api: TestApi) { #[test_connector(tags(Spatialite))] fn spatialite_column_types_must_work(api: TestApi) { let sql = r#" - SELECT InitSpatialMetaData(); - CREATE TABLE "User" ( primary_col INTEGER PRIMARY KEY ); From bb7e33c8752fa6048d3a9532bbacc5e447029e3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Tue, 28 Nov 2023 03:56:29 +0100 Subject: [PATCH 025/103] fix: Spatialite diff migration tests --- .../tests/migrations/diff.rs | 74 +++++++++++++------ 1 file changed, 53 insertions(+), 21 deletions(-) diff --git a/schema-engine/sql-migration-tests/tests/migrations/diff.rs b/schema-engine/sql-migration-tests/tests/migrations/diff.rs index b5b9dbb2250d..0a03172798f7 100644 --- a/schema-engine/sql-migration-tests/tests/migrations/diff.rs +++ b/schema-engine/sql-migration-tests/tests/migrations/diff.rs @@ -202,11 +202,19 @@ fn from_schema_datamodel_to_url(mut api: TestApi) { api.diff(input).unwrap(); - let expected_printed_messages = expect![[r#" - [ - "-- DropTable\nPRAGMA foreign_keys=off;\nDROP TABLE \"cows\";\nPRAGMA foreign_keys=on;\n\n-- CreateTable\nCREATE TABLE \"cats\" (\n \"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n \"meows\" BOOLEAN DEFAULT true\n);\n", - ] - "#]]; + let expected_printed_messages = if api.tags().contains(test_setup::Tags::Spatialite) { + expect![[r#" + [ + "-- DropTable\nPRAGMA foreign_keys=off;\nSELECT DropTable(NULL, 'cows');\nPRAGMA foreign_keys=on;\n\n-- CreateTable\nCREATE TABLE \"cats\" (\n \"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n \"meows\" BOOLEAN DEFAULT true\n);\n", + ] + "#]] + } else { + expect![[r#" + [ + "-- DropTable\nPRAGMA foreign_keys=off;\nDROP TABLE \"cows\";\nPRAGMA foreign_keys=on;\n\n-- CreateTable\nCREATE TABLE \"cats\" (\n \"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n \"meows\" BOOLEAN DEFAULT true\n);\n", + ] + "#]] + }; expected_printed_messages.assert_debug_eq(&host.printed_messages.lock().unwrap()); } @@ -249,12 +257,20 @@ fn from_schema_datasource_relative(mut api: TestApi) { }; api.diff(params).unwrap(); - - let expected_printed_messages = expect![[r#" - [ - "-- DropTable\nPRAGMA foreign_keys=off;\nDROP TABLE \"foo\";\nPRAGMA foreign_keys=on;\n", - ] - "#]]; + + let expected_printed_messages = if api.tags().contains(test_setup::Tags::Spatialite) { + expect![[r#" + [ + "-- DropTable\nPRAGMA foreign_keys=off;\nSELECT DropTable(NULL, 'foo');\nPRAGMA foreign_keys=on;\n", + ] + "#]] + } else { + expect![[r#" + [ + "-- DropTable\nPRAGMA foreign_keys=off;\nDROP TABLE \"foo\";\nPRAGMA foreign_keys=on;\n", + ] + "#]] + }; expected_printed_messages.assert_debug_eq(&host.printed_messages.lock().unwrap()); } @@ -306,11 +322,19 @@ fn from_schema_datasource_to_url(mut api: TestApi) { api.diff(input).unwrap(); - let expected_printed_messages = expect![[r#" - [ - "-- DropTable\nPRAGMA foreign_keys=off;\nDROP TABLE \"cows\";\nPRAGMA foreign_keys=on;\n\n-- CreateTable\nCREATE TABLE \"cats\" (\n \"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n \"meows\" BOOLEAN DEFAULT true\n);\n", - ] - "#]]; + let expected_printed_messages = if api.tags().contains(test_setup::Tags::Spatialite) { + expect![[r#" + [ + "-- DropTable\nPRAGMA foreign_keys=off;\nSELECT DropTable(NULL, 'cows');\nPRAGMA foreign_keys=on;\n\n-- CreateTable\nCREATE TABLE \"cats\" (\n \"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n \"meows\" BOOLEAN DEFAULT true\n);\n", + ] + "#]] + } else { + expect![[r#" + [ + "-- DropTable\nPRAGMA foreign_keys=off;\nDROP TABLE \"cows\";\nPRAGMA foreign_keys=on;\n\n-- CreateTable\nCREATE TABLE \"cats\" (\n \"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n \"meows\" BOOLEAN DEFAULT true\n);\n", + ] + "#]] + }; expected_printed_messages.assert_debug_eq(&host.printed_messages.lock().unwrap()); } @@ -348,11 +372,19 @@ fn from_url_to_url(mut api: TestApi) { api.diff(input).unwrap(); - let expected_printed_messages = expect![[r#" - [ - "-- DropTable\nPRAGMA foreign_keys=off;\nDROP TABLE \"cows\";\nPRAGMA foreign_keys=on;\n\n-- CreateTable\nCREATE TABLE \"cats\" (\n \"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n \"meows\" BOOLEAN DEFAULT true\n);\n", - ] - "#]]; + let expected_printed_messages = if api.tags().contains(test_setup::Tags::Spatialite) { + expect![[r#" + [ + "-- DropTable\nPRAGMA foreign_keys=off;\nSELECT DropTable(NULL, 'cows');\nPRAGMA foreign_keys=on;\n\n-- CreateTable\nCREATE TABLE \"cats\" (\n \"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n \"meows\" BOOLEAN DEFAULT true\n);\n", + ] + "#]] + } else { + expect![[r#" + [ + "-- DropTable\nPRAGMA foreign_keys=off;\nDROP TABLE \"cows\";\nPRAGMA foreign_keys=on;\n\n-- CreateTable\nCREATE TABLE \"cats\" (\n \"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n \"meows\" BOOLEAN DEFAULT true\n);\n", + ] + "#]] + }; expected_printed_messages.assert_debug_eq(&host.printed_messages.lock().unwrap()); } From 455b27467a424b466976837c5e77f7221006f609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Tue, 28 Nov 2023 04:05:59 +0100 Subject: [PATCH 026/103] fix: formatting --- .../sql-schema-connector/src/flavour/sqlite/connection.rs | 2 +- schema-engine/sql-migration-tests/tests/migrations/diff.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite/connection.rs b/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite/connection.rs index 47ed9ceed103..ab578047e8cc 100644 --- a/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite/connection.rs +++ b/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite/connection.rs @@ -2,7 +2,7 @@ pub(crate) use quaint::connector::rusqlite; -use quaint::connector::{GetRow, ToColumnNames, load_spatialite}; +use quaint::connector::{load_spatialite, GetRow, ToColumnNames}; use schema_connector::{ConnectorError, ConnectorResult}; use sql_schema_describer::{sqlite as describer, DescriberErrorKind, SqlSchema}; use std::sync::Mutex; diff --git a/schema-engine/sql-migration-tests/tests/migrations/diff.rs b/schema-engine/sql-migration-tests/tests/migrations/diff.rs index 0a03172798f7..aa7c4901b3c5 100644 --- a/schema-engine/sql-migration-tests/tests/migrations/diff.rs +++ b/schema-engine/sql-migration-tests/tests/migrations/diff.rs @@ -257,7 +257,7 @@ fn from_schema_datasource_relative(mut api: TestApi) { }; api.diff(params).unwrap(); - + let expected_printed_messages = if api.tags().contains(test_setup::Tags::Spatialite) { expect![[r#" [ From 35a9f15ba90cc36178fcd5706d559b82b32dca56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Tue, 28 Nov 2023 10:52:06 +0100 Subject: [PATCH 027/103] fix: revert Sqlite total queries to 9 --- .../query-engine-tests/tests/new/metrics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/new/metrics.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/new/metrics.rs index 0c1e3788c5fa..869cb1e57013 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/new/metrics.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/new/metrics.rs @@ -35,7 +35,7 @@ mod metrics { let total_operations = get_counter(&json, PRISMA_CLIENT_QUERIES_TOTAL); match runner.connector_version() { - Sqlite(_) => assert_eq!(total_queries, 10), + Sqlite(_) => assert_eq!(total_queries, 9), SqlServer(_) => assert_eq!(total_queries, 17), MongoDb(_) => assert_eq!(total_queries, 5), CockroachDb(_) => (), // not deterministic From 7b8348c5b7becf3bb42da72a2b3f87c0b7699daf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Tue, 28 Nov 2023 10:54:27 +0100 Subject: [PATCH 028/103] fix: install Spatialite with sudo --- .github/workflows/test-query-engine.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-query-engine.yml b/.github/workflows/test-query-engine.yml index 03da84f114a9..a985e2151ed9 100644 --- a/.github/workflows/test-query-engine.yml +++ b/.github/workflows/test-query-engine.yml @@ -119,7 +119,7 @@ jobs: - name: Install Spatialite if: ${{ matrix.database.name == 'spatialite' }} - run: apt install -y libsqlite3-mod-spatialite + run: sudo apt install -y libsqlite3-mod-spatialite - run: export WORKSPACE_ROOT=$(pwd) && cargo test --package query-engine-tests -- --test-threads=1 if: ${{ matrix.database.single_threaded }} From 31228b58c12ac2d3633d0e8a8fd4f8e15add6ee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Wed, 29 Nov 2023 23:14:23 +0100 Subject: [PATCH 029/103] fix: add WGS84_ONLY option to `InitSpatialMetadata` and only call the function if necessary --- quaint/src/connector/sqlite/native/mod.rs | 13 +++++-- .../writes/data_types/native_types/sqlite.rs | 34 +++++++++---------- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/quaint/src/connector/sqlite/native/mod.rs b/quaint/src/connector/sqlite/native/mod.rs index 4dc8a7d056c1..157fa527b703 100644 --- a/quaint/src/connector/sqlite/native/mod.rs +++ b/quaint/src/connector/sqlite/native/mod.rs @@ -36,11 +36,20 @@ pub fn load_spatialite(conn: &rusqlite::Connection) -> crate::Result<()> { unsafe { let _guard = LoadExtensionGuard::new(conn)?; conn.load_extension(spatialite_path, None)?; - conn.query_row("SELECT InitSpatialMetaData(1)", [], |_| Ok(())).unwrap(); + } + return match conn.query_row("SELECT CheckSpatialMetaData()", [], |r| r.get(0))? { + 0 => { + match conn.query_row("SELECT InitSpatialMetaData(1, 'WGS84_ONLY')", [], |r| r.get(0))? { + 1 => Ok(()), + _ => Err(Error::builder(ErrorKind::QueryError("Failed to load Spatialite".into())).build()), + } + }, + 3 => Ok(()), + _ => Err(Error::builder(ErrorKind::ConnectionError("Invalid Spatialite State".into())).build()) } } } - Ok(()) + return Ok(()) } impl TryFrom<&str> for Sqlite { diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sqlite.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sqlite.rs index 338278c9166f..5d7a338c98ab 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sqlite.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sqlite.rs @@ -60,14 +60,14 @@ mod sqlite { let schema = indoc! { r#"model Model { #id(id, String, @id, @default(cuid())) - geometry Geometry @test.Geometry(Geometry, 3857) - geometry_point Geometry @test.Geometry(Point, 3857) - geometry_line Geometry @test.Geometry(LineString, 3857) - geometry_poly Geometry @test.Geometry(Polygon, 3857) - geometry_multipoint Geometry @test.Geometry(MultiPoint, 3857) - geometry_multiline Geometry @test.Geometry(MultiLineString, 3857) - geometry_multipoly Geometry @test.Geometry(MultiPolygon, 3857) - geometry_collection Geometry @test.Geometry(GeometryCollection, 3857) + geometry Geometry @test.Geometry(Geometry, 4326) + geometry_point Geometry @test.Geometry(Point, 4326) + geometry_line Geometry @test.Geometry(LineString, 4326) + geometry_poly Geometry @test.Geometry(Polygon, 4326) + geometry_multipoint Geometry @test.Geometry(MultiPoint, 4326) + geometry_multiline Geometry @test.Geometry(MultiLineString, 4326) + geometry_multipoly Geometry @test.Geometry(MultiPolygon, 4326) + geometry_collection Geometry @test.Geometry(GeometryCollection, 4326) }"# }; @@ -81,14 +81,14 @@ mod sqlite { run_query!(&runner, r#"mutation { createOneModel( data: { - geometry: "SRID=3857;POINT(1 2)" - geometry_point: "SRID=3857;POINT(1 2)" - geometry_line: "SRID=3857;LINESTRING(1 2,3 4)" - geometry_poly: "SRID=3857;POLYGON((1 2,3 4,5 6,1 2))" - geometry_multipoint: "SRID=3857;MULTIPOINT(1 2)" - geometry_multiline: "SRID=3857;MULTILINESTRING((1 2,3 4))" - geometry_multipoly: "SRID=3857;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))" - geometry_collection: "SRID=3857;GEOMETRYCOLLECTION(POINT(1 2))" + geometry: "SRID=4326;POINT(1 2)" + geometry_point: "SRID=4326;POINT(1 2)" + geometry_line: "SRID=4326;LINESTRING(1 2,3 4)" + geometry_poly: "SRID=4326;POLYGON((1 2,3 4,5 6,1 2))" + geometry_multipoint: "SRID=4326;MULTIPOINT(1 2)" + geometry_multiline: "SRID=4326;MULTILINESTRING((1 2,3 4))" + geometry_multipoly: "SRID=4326;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))" + geometry_collection: "SRID=4326;GEOMETRYCOLLECTION(POINT(1 2))" } ) { geometry @@ -101,7 +101,7 @@ mod sqlite { geometry_collection } }"#), - @r###"{"data":{"createOneModel":{"geometry":"SRID=3857;POINT(1 2)","geometry_point":"SRID=3857;POINT(1 2)","geometry_line":"SRID=3857;LINESTRING(1 2,3 4)","geometry_poly":"SRID=3857;POLYGON((1 2,3 4,5 6,1 2))","geometry_multipoint":"SRID=3857;MULTIPOINT(1 2)","geometry_multiline":"SRID=3857;MULTILINESTRING((1 2,3 4))","geometry_multipoly":"SRID=3857;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))","geometry_collection":"SRID=3857;GEOMETRYCOLLECTION(POINT(1 2))"}}}"### + @r###"{"data":{"createOneModel":{"geometry":"SRID=4326;POINT(1 2)","geometry_point":"SRID=4326;POINT(1 2)","geometry_line":"SRID=4326;LINESTRING(1 2,3 4)","geometry_poly":"SRID=4326;POLYGON((1 2,3 4,5 6,1 2))","geometry_multipoint":"SRID=4326;MULTIPOINT(1 2)","geometry_multiline":"SRID=4326;MULTILINESTRING((1 2,3 4))","geometry_multipoly":"SRID=4326;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))","geometry_collection":"SRID=4326;GEOMETRYCOLLECTION(POINT(1 2))"}}}"### ); Ok(()) From 8a5288b359fb26f1cc688e037a42ee311019f3c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Wed, 29 Nov 2023 23:26:50 +0100 Subject: [PATCH 030/103] fix: formatting --- quaint/src/connector/sqlite/native/mod.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/quaint/src/connector/sqlite/native/mod.rs b/quaint/src/connector/sqlite/native/mod.rs index 157fa527b703..ca2b3c8b4d57 100644 --- a/quaint/src/connector/sqlite/native/mod.rs +++ b/quaint/src/connector/sqlite/native/mod.rs @@ -38,18 +38,16 @@ pub fn load_spatialite(conn: &rusqlite::Connection) -> crate::Result<()> { conn.load_extension(spatialite_path, None)?; } return match conn.query_row("SELECT CheckSpatialMetaData()", [], |r| r.get(0))? { - 0 => { - match conn.query_row("SELECT InitSpatialMetaData(1, 'WGS84_ONLY')", [], |r| r.get(0))? { - 1 => Ok(()), - _ => Err(Error::builder(ErrorKind::QueryError("Failed to load Spatialite".into())).build()), - } + 0 => match conn.query_row("SELECT InitSpatialMetaData(1, 'WGS84_ONLY')", [], |r| r.get(0))? { + 1 => Ok(()), + _ => Err(Error::builder(ErrorKind::QueryError("Failed to load Spatialite".into())).build()), }, 3 => Ok(()), - _ => Err(Error::builder(ErrorKind::ConnectionError("Invalid Spatialite State".into())).build()) - } + _ => Err(Error::builder(ErrorKind::ConnectionError("Invalid Spatialite State".into())).build()), + }; } } - return Ok(()) + Ok(()) } impl TryFrom<&str> for Sqlite { From e0f834dc25d3a4b4c821df9810dfd890335c0b86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Thu, 30 Nov 2023 15:33:33 +0100 Subject: [PATCH 031/103] fix: skip geometric_comparison_filters test for MariaDB while we figure it out --- .../tests/queries/filters/geometry_filter.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs index 3fc5c3d7a797..4b4e2a200787 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs @@ -111,9 +111,11 @@ mod geometry_filter_spec { where_shorthands_test(runner).await } + // This test should work for MariaDB but doesn't so we skip it for now, + // see discussion here: https://github.com/prisma/prisma-engines/pull/4208#issuecomment-1828997865 #[connector_test( schema(schema), - exclude(Postgres, Sqlite(3, "libsql.js")), + exclude(Postgres, Sqlite(3, "libsql.js"), MySQL("mariadb")), capabilities(GeometryFiltering) )] async fn geometric_comparison_filters(runner: Runner) -> TestResult<()> { From f7f28926514b68644d20eda22ecb6e2a7259e081 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Thu, 30 Nov 2023 16:48:52 +0100 Subject: [PATCH 032/103] refactor: return conversion error in GeometryValue::from_str --- quaint/src/ast/values.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/quaint/src/ast/values.rs b/quaint/src/ast/values.rs index f2185b8d6c42..53c5d7e1ca00 100644 --- a/quaint/src/ast/values.rs +++ b/quaint/src/ast/values.rs @@ -53,7 +53,7 @@ impl Display for GeometryValue { } impl FromStr for GeometryValue { - type Err = String; + type Err = Error; fn from_str(s: &str) -> Result { static EWKT_REGEX: Lazy = Lazy::new(|| Regex::new(r"^(SRID=(?P\d+);)?(?P.+)$").unwrap()); @@ -63,12 +63,12 @@ impl FromStr for GeometryValue { let srid = match capture.name("srid").map(|v| v.as_str().parse::()) { None => Ok(0), Some(Ok(srid)) => Ok(srid), - Some(Err(_)) => Err("Invalid SRID"), + Some(Err(_)) => Err(Error::builder(ErrorKind::conversion("Invalid EWKT SRID")).build()), }?; let wkt = capture.name("geometry").map(|v| v.as_str()).unwrap().to_string(); Ok(GeometryValue { srid, wkt }) }) - .ok_or("Invalid EWKT".to_string())? + .ok_or_else(|| Error::builder(ErrorKind::conversion("Invalid EWKT string")).build())? } } From 858653f25eb29f9d99de5c7933e0fb107fd18a0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Sun, 4 Aug 2024 21:39:24 +0200 Subject: [PATCH 033/103] refactor: simplify spatialite CI setup --- .github/workflows/test-query-engine-template.yml | 4 +--- .github/workflows/test-schema-engine.yml | 6 +----- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/.github/workflows/test-query-engine-template.yml b/.github/workflows/test-query-engine-template.yml index aee9b400c51d..06a35c076662 100644 --- a/.github/workflows/test-query-engine-template.yml +++ b/.github/workflows/test-query-engine-template.yml @@ -68,16 +68,14 @@ jobs: - name: Install Spatialite if: ${{ inputs.name == 'spatialite' }} - run: sudo apt install -y libsqlite3-mod-spatialite + run: sudo apt install -y libsqlite3-mod-spatialite && echo "SPATIALITE_PATH=mod_spatialite" >> $GITHUB_ENV - run: export WORKSPACE_ROOT=$(pwd) && cargo nextest run -p query-engine-tests --partition hash:${{ matrix.partition }} --test-threads=1 if: ${{ inputs.single_threaded }} env: CLICOLOR_FORCE: 1 - SPATIALITE_PATH: ${{ inputs.name == 'spatialite' && 'mod_spatialite' || null }} - run: export WORKSPACE_ROOT=$(pwd) && cargo nextest run -p query-engine-tests --partition hash:${{ matrix.partition }} --test-threads=8 if: ${{ !inputs.single_threaded }} env: CLICOLOR_FORCE: 1 - SPATIALITE_PATH: ${{ inputs.name == 'spatialite' && 'mod_spatialite' || null }} diff --git a/.github/workflows/test-schema-engine.yml b/.github/workflows/test-schema-engine.yml index ec08cdb22c86..5fbb7829a5a6 100644 --- a/.github/workflows/test-schema-engine.yml +++ b/.github/workflows/test-schema-engine.yml @@ -127,7 +127,7 @@ jobs: - name: Install Spatialite if: ${{ matrix.database.name == 'spatialite' }} - run: sudo apt install -y libsqlite3-mod-spatialite + run: sudo apt install -y libsqlite3-mod-spatialite && echo "SPATIALITE_PATH=mod_spatialite" >> $GITHUB_ENV - name: "Start ${{ matrix.database.name }}" run: make start-${{ matrix.database.name }} @@ -137,28 +137,24 @@ jobs: env: CLICOLOR_FORCE: 1 TEST_DATABASE_URL: ${{ matrix.database.url }} - SPATIALITE_PATH: ${{ matrix.database.name == 'spatialite' && 'mod_spatialite' || null }} - run: cargo nextest run -p sql-schema-describer if: ${{ !matrix.database.single_threaded }} env: CLICOLOR_FORCE: 1 TEST_DATABASE_URL: ${{ matrix.database.url }} - SPATIALITE_PATH: ${{ matrix.database.name == 'spatialite' && 'mod_spatialite' || null }} - run: cargo nextest run -p sql-migration-tests if: ${{ !matrix.database.single_threaded }} env: CLICOLOR_FORCE: 1 TEST_DATABASE_URL: ${{ matrix.database.url }} - SPATIALITE_PATH: ${{ matrix.database.name == 'spatialite' && 'mod_spatialite' || null }} - run: cargo nextest run -p schema-engine-cli if: ${{ !matrix.database.single_threaded }} env: CLICOLOR_FORCE: 1 TEST_DATABASE_URL: ${{ matrix.database.url }} - SPATIALITE_PATH: ${{ matrix.database.name == 'spatialite' && 'mod_spatialite' || null }} # # Vitess tests From f7f25c985b11158d1b13a26b663bb4ad5347bceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Wed, 25 Sep 2024 22:39:40 +0200 Subject: [PATCH 034/103] Fix toolchain, features and lint --- psl/psl-core/src/lib.rs | 1 + quaint/Cargo.toml | 1 - query-engine/schema/src/build/utils.rs | 2 +- rust-toolchain.toml | 2 +- schema-engine/connectors/sql-schema-connector/src/flavour.rs | 2 +- .../connectors/sql-schema-connector/src/flavour/sqlite.rs | 2 +- schema-engine/sql-migration-tests/src/test_api.rs | 2 +- 7 files changed, 6 insertions(+), 6 deletions(-) diff --git a/psl/psl-core/src/lib.rs b/psl/psl-core/src/lib.rs index addb6316236c..6387ec7cfa72 100644 --- a/psl/psl-core/src/lib.rs +++ b/psl/psl-core/src/lib.rs @@ -1,6 +1,7 @@ #![doc = include_str!("../README.md")] #![deny(rust_2018_idioms, unsafe_code)] #![allow(clippy::derive_partial_eq_without_eq)] +#![allow(incomplete_features)] #![feature(repr128)] pub mod builtin_connectors; diff --git a/quaint/Cargo.toml b/quaint/Cargo.toml index c6b4ad0c1794..7ee632146d91 100644 --- a/quaint/Cargo.toml +++ b/quaint/Cargo.toml @@ -85,7 +85,6 @@ uuid.workspace = true crosstarget-utils = { path = "../libs/crosstarget-utils" } concat-idents = "1.1.5" once_cell = "1.3" -regex = "1.10.2" geozero = { version = "0.11.0", default-features = false, features = ["with-wkb", "with-geojson"] } [dev-dependencies] diff --git a/query-engine/schema/src/build/utils.rs b/query-engine/schema/src/build/utils.rs index d7ee3106d230..56491ec26742 100644 --- a/query-engine/schema/src/build/utils.rs +++ b/query-engine/schema/src/build/utils.rs @@ -66,7 +66,7 @@ pub(crate) fn simple_input_field<'a>( name: impl Into>, field_type: InputType<'a>, default_value: Option, -) -> InputField<'_> { +) -> InputField<'a> { input_field(name, vec![field_type], default_value) } diff --git a/rust-toolchain.toml b/rust-toolchain.toml index e48263a13878..9fcff05a670c 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "1.80.1" +channel = "nightly" components = ["clippy", "rustfmt", "rust-src"] targets = [ # WASM target for serverless and edge environments. diff --git a/schema-engine/connectors/sql-schema-connector/src/flavour.rs b/schema-engine/connectors/sql-schema-connector/src/flavour.rs index 3b2e901bcd67..f4ba1264ee80 100644 --- a/schema-engine/connectors/sql-schema-connector/src/flavour.rs +++ b/schema-engine/connectors/sql-schema-connector/src/flavour.rs @@ -258,7 +258,7 @@ pub(crate) trait SqlFlavour: &'a mut self, sql: &'a str, params: &'a [quaint::prelude::Value<'a>], - ) -> BoxFuture<'_, ConnectorResult>; + ) -> BoxFuture<'a, ConnectorResult>; fn raw_cmd<'a>(&'a mut self, sql: &'a str) -> BoxFuture<'a, ConnectorResult<()>>; diff --git a/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite.rs b/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite.rs index 2ea1e21f67fb..e3ec9775165f 100644 --- a/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite.rs +++ b/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite.rs @@ -364,7 +364,7 @@ impl SqlFlavour for SqliteFlavour { migrations: &'a [MigrationDirectory], _shadow_database_connection_string: Option, _namespaces: Option, - ) -> BoxFuture<'_, ConnectorResult> { + ) -> BoxFuture<'a, ConnectorResult> { Box::pin(async move { tracing::debug!("Applying migrations to temporary in-memory SQLite database."); let mut shadow_db_conn = Connection::new_in_memory(); diff --git a/schema-engine/sql-migration-tests/src/test_api.rs b/schema-engine/sql-migration-tests/src/test_api.rs index 6d67bbd98491..7ef12728463b 100644 --- a/schema-engine/sql-migration-tests/src/test_api.rs +++ b/schema-engine/sql-migration-tests/src/test_api.rs @@ -310,7 +310,7 @@ impl TestApi { MarkMigrationRolledBack::new(&mut self.connector, migration_name.into()) } - pub fn migration_persistence<'a>(&'a mut self) -> &mut (dyn MigrationPersistence + 'a) { + pub fn migration_persistence<'a>(&'a mut self) -> &'a mut (dyn MigrationPersistence + 'a) { &mut self.connector } From 0a879b4a4191f546c6b15019d3bd459f3a958bee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 30 Sep 2024 22:52:21 +0200 Subject: [PATCH 035/103] Add JSArgType::Geometry --- query-engine/driver-adapters/src/conversion/js_arg_type.rs | 4 ++++ .../connectors/sql-schema-connector/src/sql_doc_parser.rs | 2 ++ 2 files changed, 6 insertions(+) diff --git a/query-engine/driver-adapters/src/conversion/js_arg_type.rs b/query-engine/driver-adapters/src/conversion/js_arg_type.rs index e1ea7c1c5754..ea66d807c06f 100644 --- a/query-engine/driver-adapters/src/conversion/js_arg_type.rs +++ b/query-engine/driver-adapters/src/conversion/js_arg_type.rs @@ -40,6 +40,8 @@ pub enum JSArgType { Date, /// A time value. Time, + /// A geometry value. + Geometry, } impl core::fmt::Display for JSArgType { @@ -63,6 +65,7 @@ impl core::fmt::Display for JSArgType { JSArgType::DateTime => "DateTime", JSArgType::Date => "Date", JSArgType::Time => "Time", + JSArgType::Geometry => "Geometry", }; write!(f, "{}", s) @@ -89,5 +92,6 @@ pub fn value_to_js_arg_type(value: &quaint::Value) -> JSArgType { quaint::ValueType::DateTime(_) => JSArgType::DateTime, quaint::ValueType::Date(_) => JSArgType::Date, quaint::ValueType::Time(_) => JSArgType::Time, + quaint::ValueType::Geometry(_) | quaint::ValueType::Geography(_) => JSArgType::Geometry, } } diff --git a/schema-engine/connectors/sql-schema-connector/src/sql_doc_parser.rs b/schema-engine/connectors/sql-schema-connector/src/sql_doc_parser.rs index 819621512b30..f6e82eb86a7e 100644 --- a/schema-engine/connectors/sql-schema-connector/src/sql_doc_parser.rs +++ b/schema-engine/connectors/sql-schema-connector/src/sql_doc_parser.rs @@ -218,6 +218,8 @@ fn parse_typ_opt<'a>( ScalarType::Json => ColumnType::Json, ScalarType::Bytes => ColumnType::Bytes, ScalarType::Decimal => ColumnType::Numeric, + ScalarType::GeoJson | ScalarType::Geometry => ColumnType::Geometry, + }) .map(ParsedParamType::ColumnType) .or_else(|| { From e8658e95860fbc09de3b0c187001b699f4d6964d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 30 Sep 2024 23:12:20 +0200 Subject: [PATCH 036/103] Fix: fmt --- prisma-fmt/src/lib.rs | 1 + prisma-schema-wasm/src/lib.rs | 1 + psl/psl-core/src/lib.rs | 1 + .../validation_pipeline/validations/models.rs | 4 ++-- .../connector-test-kit-rs/qe-setup/src/lib.rs | 1 + .../query-tests-setup/src/logging.rs | 1 + .../query-tests-setup/src/schema_gen/parse.rs | 1 + .../src/root_queries/aggregate.rs | 10 +++++----- .../core/src/query_document/parser.rs | 4 ++-- .../core/src/telemetry/capturing/capturer.rs | 1 + .../src/conversion/js_to_quaint.rs | 1 - query-engine/query-engine/src/server/mod.rs | 5 +---- .../schema-connector/src/namespaces.rs | 1 + .../src/sql_doc_parser.rs | 1 - .../src/sql_renderer/postgres_renderer.rs | 2 +- .../sql-migration-tests/src/assertions.rs | 20 ++++++++----------- .../src/commands/schema_push.rs | 10 ++++------ 17 files changed, 31 insertions(+), 34 deletions(-) diff --git a/prisma-fmt/src/lib.rs b/prisma-fmt/src/lib.rs index 3ec5514313bd..7f6da32e3464 100644 --- a/prisma-fmt/src/lib.rs +++ b/prisma-fmt/src/lib.rs @@ -205,6 +205,7 @@ pub fn validate(validate_params: String) -> Result<(), String> { } /// Given a list of Prisma schema files (and their locations), returns the merged schema. +/// /// This is useful for `@prisma/client` generation, where the client needs a single - potentially large - schema, /// while still allowing the user to split their schema copies into multiple files. /// Internally, it uses `[validate]`. diff --git a/prisma-schema-wasm/src/lib.rs b/prisma-schema-wasm/src/lib.rs index 8ef24cbcdfb3..46b9dee6bc68 100644 --- a/prisma-schema-wasm/src/lib.rs +++ b/prisma-schema-wasm/src/lib.rs @@ -124,6 +124,7 @@ pub fn references(schema: String, params: String) -> String { } /// This api is modelled on an LSP [hover request](https://github.com/microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-16.md#hover-request-leftwards_arrow_with_hook). +/// /// Input and output are both JSON, the request being a `HoverParams` object /// and the response being a `Hover` object. #[wasm_bindgen] diff --git a/psl/psl-core/src/lib.rs b/psl/psl-core/src/lib.rs index 6387ec7cfa72..dac097aa17ea 100644 --- a/psl/psl-core/src/lib.rs +++ b/psl/psl-core/src/lib.rs @@ -111,6 +111,7 @@ pub fn validate_multi_file(files: &[(String, SourceFile)], connectors: Connector } /// Retrieves a Prisma schema without validating it. +/// /// You should only use this method when actually validating the schema is too expensive /// computationally or in terms of bundle size (e.g., for `query-engine-wasm`). pub fn parse_without_validation(file: SourceFile, connectors: ConnectorRegistry<'_>) -> ValidatedSchema { diff --git a/psl/psl-core/src/validate/validation_pipeline/validations/models.rs b/psl/psl-core/src/validate/validation_pipeline/validations/models.rs index a53063624b2d..bc72226dcb5d 100644 --- a/psl/psl-core/src/validate/validation_pipeline/validations/models.rs +++ b/psl/psl-core/src/validate/validation_pipeline/validations/models.rs @@ -226,12 +226,12 @@ pub(crate) fn primary_key_connector_specific(model: ModelWalker<'_>, ctx: &mut C } if primary_key.fields().len() > 1 && !ctx.has_capability(ConnectorCapability::CompoundIds) { - return ctx.push_error(DatamodelError::new_model_validation_error( + ctx.push_error(DatamodelError::new_model_validation_error( "The current connector does not support compound ids.", container_type, model.name(), primary_key.ast_attribute().span, - )); + )) } } diff --git a/query-engine/connector-test-kit-rs/qe-setup/src/lib.rs b/query-engine/connector-test-kit-rs/qe-setup/src/lib.rs index c1e6842d9bf8..5912ca6b9570 100644 --- a/query-engine/connector-test-kit-rs/qe-setup/src/lib.rs +++ b/query-engine/connector-test-kit-rs/qe-setup/src/lib.rs @@ -60,6 +60,7 @@ fn parse_configuration(datamodel: &str) -> ConnectorResult<(Datasource, String, } /// Database setup for connector-test-kit-rs with Driver Adapters. +/// /// If the external driver adapter requires a migration by means of the JavaScript runtime /// (rather than just the Schema Engine), this function will call [`ExternalInitializer::init_with_migration`]. /// Otherwise, it will call [`ExternalInitializer::init`], and then proceed with the standard diff --git a/query-engine/connector-test-kit-rs/query-tests-setup/src/logging.rs b/query-engine/connector-test-kit-rs/query-tests-setup/src/logging.rs index 5520075e6d30..bb7d15458158 100644 --- a/query-engine/connector-test-kit-rs/query-tests-setup/src/logging.rs +++ b/query-engine/connector-test-kit-rs/query-tests-setup/src/logging.rs @@ -20,6 +20,7 @@ pub fn test_tracing_subscriber(log_config: String, metrics: MetricRegistry, log_ } /// This is a temporary implementation detail for `tracing` logs in tests. +/// /// Instead of going through `std::io::stderr`, it goes through the specific /// local stderr handle used by `eprintln` and `dbg`, allowing logs to appear in /// specific test outputs for readability. diff --git a/query-engine/connector-test-kit-rs/query-tests-setup/src/schema_gen/parse.rs b/query-engine/connector-test-kit-rs/query-tests-setup/src/schema_gen/parse.rs index 509fc188883f..1b91dad84b81 100644 --- a/query-engine/connector-test-kit-rs/query-tests-setup/src/schema_gen/parse.rs +++ b/query-engine/connector-test-kit-rs/query-tests-setup/src/schema_gen/parse.rs @@ -38,6 +38,7 @@ pub fn parse_id(field: &str, json: &serde_json::Value, path: &[&str], meta: &str } /// Parses the JSON result of mutation sent to the Query Engine in order to extract the generated compound ids. +/// /// Returns a string that's already formatted to be included in another query. eg: /// { "id_1_id_2": { id_1: "my_fancy_id_1", id_2: "my_fancy_id_2" } } pub fn parse_compound_id( diff --git a/query-engine/connectors/mongodb-query-connector/src/root_queries/aggregate.rs b/query-engine/connectors/mongodb-query-connector/src/root_queries/aggregate.rs index 05ff57053e95..797e34127f8a 100644 --- a/query-engine/connectors/mongodb-query-connector/src/root_queries/aggregate.rs +++ b/query-engine/connectors/mongodb-query-connector/src/root_queries/aggregate.rs @@ -108,7 +108,7 @@ fn to_aggregation_rows( for field in fields { let meta = selection_meta.get(field.db_name()).unwrap(); - let bson = doc.remove(&format!("count_{}", field.db_name())).unwrap(); + let bson = doc.remove(format!("count_{}", field.db_name())).unwrap(); let field_val = value_from_bson(bson, meta)?; row.push(AggregationResult::Count(Some(field.clone()), field_val)); @@ -117,7 +117,7 @@ fn to_aggregation_rows( AggregationSelection::Average(fields) => { for field in fields { let meta = selection_meta.get(field.db_name()).unwrap(); - let bson = doc.remove(&format!("avg_{}", field.db_name())).unwrap(); + let bson = doc.remove(format!("avg_{}", field.db_name())).unwrap(); let field_val = value_from_bson(bson, meta)?; row.push(AggregationResult::Average(field.clone(), field_val)); @@ -126,7 +126,7 @@ fn to_aggregation_rows( AggregationSelection::Sum(fields) => { for field in fields { let meta = selection_meta.get(field.db_name()).unwrap(); - let bson = doc.remove(&format!("sum_{}", field.db_name())).unwrap(); + let bson = doc.remove(format!("sum_{}", field.db_name())).unwrap(); let field_val = value_from_bson(bson, meta)?; row.push(AggregationResult::Sum(field.clone(), field_val)); @@ -135,7 +135,7 @@ fn to_aggregation_rows( AggregationSelection::Min(fields) => { for field in fields { let meta = selection_meta.get(field.db_name()).unwrap(); - let bson = doc.remove(&format!("min_{}", field.db_name())).unwrap(); + let bson = doc.remove(format!("min_{}", field.db_name())).unwrap(); let field_val = value_from_bson(bson, meta)?; row.push(AggregationResult::Min(field.clone(), field_val)); @@ -144,7 +144,7 @@ fn to_aggregation_rows( AggregationSelection::Max(fields) => { for field in fields { let meta = selection_meta.get(field.db_name()).unwrap(); - let bson = doc.remove(&format!("max_{}", field.db_name())).unwrap(); + let bson = doc.remove(format!("max_{}", field.db_name())).unwrap(); let field_val = value_from_bson(bson, meta)?; row.push(AggregationResult::Max(field.clone(), field_val)); diff --git a/query-engine/core/src/query_document/parser.rs b/query-engine/core/src/query_document/parser.rs index a216d82fea53..f89540ff8ecc 100644 --- a/query-engine/core/src/query_document/parser.rs +++ b/query-engine/core/src/query_document/parser.rs @@ -122,10 +122,10 @@ impl QueryDocumentParser { ) .and_then(move |arguments| { if !selection.nested_selections().is_empty() && schema_field.field_type().is_scalar() { - return Err(ValidationError::selection_set_on_scalar( + Err(ValidationError::selection_set_on_scalar( selection.name().to_string(), selection_path.segments(), - )); + )) } else { // If the output type of the field is an object type of any form, validate the sub selection as well. let nested_fields = schema_field.field_type().as_object_type().map(|obj| { diff --git a/query-engine/core/src/telemetry/capturing/capturer.rs b/query-engine/core/src/telemetry/capturing/capturer.rs index d0d9886acd2b..290a2737f48a 100644 --- a/query-engine/core/src/telemetry/capturing/capturer.rs +++ b/query-engine/core/src/telemetry/capturing/capturer.rs @@ -9,6 +9,7 @@ use opentelemetry::{ }; /// Capturer determines, based on a set of settings and a trace id, how capturing is going to be handled. +/// /// Generally, both the trace id and the settings will be derived from request headers. Thus, a new /// value of this enum is created per request. #[derive(Debug, Clone)] diff --git a/query-engine/driver-adapters/src/conversion/js_to_quaint.rs b/query-engine/driver-adapters/src/conversion/js_to_quaint.rs index 0ae3e4ad2698..66b2c22e4fcd 100644 --- a/query-engine/driver-adapters/src/conversion/js_to_quaint.rs +++ b/query-engine/driver-adapters/src/conversion/js_to_quaint.rs @@ -285,7 +285,6 @@ pub fn js_value_to_quaint( ColumnType::UuidArray => js_array_to_quaint(ColumnType::Uuid, json_value, column_name), // TODO@geometry: Probably need to add geometry value handling here - unimplemented => { todo!("support column type {:?} in column {}", unimplemented, column_name) } diff --git a/query-engine/query-engine/src/server/mod.rs b/query-engine/query-engine/src/server/mod.rs index 01b61a07b6b4..0b6ef2245ad5 100644 --- a/query-engine/query-engine/src/server/mod.rs +++ b/query-engine/query-engine/src/server/mod.rs @@ -227,10 +227,7 @@ async fn metrics_handler(cx: Arc, req: Request) -> Result = match serde_json::from_slice(full_body.as_ref()) { - Ok(map) => map, - Err(_e) => HashMap::new(), - }; + let global_labels: HashMap = serde_json::from_slice(full_body.as_ref()).unwrap_or_default(); let response = if requested_json { let metrics = cx.metrics.to_json(global_labels); diff --git a/schema-engine/connectors/schema-connector/src/namespaces.rs b/schema-engine/connectors/schema-connector/src/namespaces.rs index d35f82df0f0d..f59d8cb3474f 100644 --- a/schema-engine/connectors/schema-connector/src/namespaces.rs +++ b/schema-engine/connectors/schema-connector/src/namespaces.rs @@ -1,6 +1,7 @@ //! Namespaces are used in conjunction with the MultiSchema preview feature. /// A nonempty set of namespaces. +/// /// It is assumed that the namespaces are unique. /// It is often passed around an Option for when /// the namespaces cannot be inferred, or when the MultiSchema preview diff --git a/schema-engine/connectors/sql-schema-connector/src/sql_doc_parser.rs b/schema-engine/connectors/sql-schema-connector/src/sql_doc_parser.rs index f6e82eb86a7e..ebdf6297ceef 100644 --- a/schema-engine/connectors/sql-schema-connector/src/sql_doc_parser.rs +++ b/schema-engine/connectors/sql-schema-connector/src/sql_doc_parser.rs @@ -219,7 +219,6 @@ fn parse_typ_opt<'a>( ScalarType::Bytes => ColumnType::Bytes, ScalarType::Decimal => ColumnType::Numeric, ScalarType::GeoJson | ScalarType::Geometry => ColumnType::Geometry, - }) .map(ParsedParamType::ColumnType) .or_else(|| { diff --git a/schema-engine/connectors/sql-schema-connector/src/sql_renderer/postgres_renderer.rs b/schema-engine/connectors/sql-schema-connector/src/sql_renderer/postgres_renderer.rs index b63e6798d173..121255b11fb4 100644 --- a/schema-engine/connectors/sql-schema-connector/src/sql_renderer/postgres_renderer.rs +++ b/schema-engine/connectors/sql-schema-connector/src/sql_renderer/postgres_renderer.rs @@ -8,7 +8,7 @@ use crate::{ }, sql_schema_differ::{ColumnChange, ColumnChanges}, }; -use psl::builtin_connectors::{CockroachType, PostgresType, geometry::GeometryParams}; +use psl::builtin_connectors::{geometry::GeometryParams, CockroachType, PostgresType}; use sql_ddl::{ postgres::{self as ddl, PostgresIdentifier}, IndexColumn, SortOrder, diff --git a/schema-engine/sql-migration-tests/src/assertions.rs b/schema-engine/sql-migration-tests/src/assertions.rs index e32554a451b5..6a2598edfb38 100644 --- a/schema-engine/sql-migration-tests/src/assertions.rs +++ b/schema-engine/sql-migration-tests/src/assertions.rs @@ -191,13 +191,11 @@ impl SchemaAssertion { } fn print_context(&self) { - match &self.context { - Some(context) => println!("Test failure with context <{}>", context.red()), - None => {} + if let Some(context) = &self.context { + println!("Test failure with context <{}>", context.red()) } - match &self.description { - Some(description) => println!("{}: {}", "Description".bold(), description.italic()), - None => {} + if let Some(description) = &self.description { + println!("{}: {}", "Description".bold(), description.italic()) } } @@ -325,13 +323,11 @@ pub struct TableAssertion<'a> { impl<'a> TableAssertion<'a> { fn print_context(&self) { - match &self.context { - Some(context) => println!("Test failure with context <{}>", context.red()), - None => {} + if let Some(context) = &self.context { + println!("Test failure with context <{}>", context.red()) } - match &self.description { - Some(description) => println!("{}: {}", "Description".bold(), description.italic()), - None => {} + if let Some(description) = &self.description { + println!("{}: {}", "Description".bold(), description.italic()) } } diff --git a/schema-engine/sql-migration-tests/src/commands/schema_push.rs b/schema-engine/sql-migration-tests/src/commands/schema_push.rs index f7442b3a72c4..f20121f7b3aa 100644 --- a/schema-engine/sql-migration-tests/src/commands/schema_push.rs +++ b/schema-engine/sql-migration-tests/src/commands/schema_push.rs @@ -102,13 +102,11 @@ impl SchemaPushAssertion { } pub fn print_context(&self) { - match &self.context { - Some(context) => println!("Test failure with context <{}>", context.red()), - None => {} + if let Some(context) = &self.context { + println!("Test failure with context <{}>", context.red()) } - match &self.description { - Some(description) => println!("{}: {}", "Description".bold(), description.italic()), - None => {} + if let Some(description) = &self.description { + println!("{}: {}", "Description".bold(), description.italic()) } } From f74d4de072d4255d02016e208bc2b4b644cd7cee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 30 Sep 2024 23:26:00 +0200 Subject: [PATCH 037/103] Fix test_native_types_multifile --- prisma-fmt/tests/native_types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prisma-fmt/tests/native_types.rs b/prisma-fmt/tests/native_types.rs index ef8712ed1a37..b1000b113716 100644 --- a/prisma-fmt/tests/native_types.rs +++ b/prisma-fmt/tests/native_types.rs @@ -38,7 +38,7 @@ fn test_native_types_multifile() { let result = prisma_fmt::native_types(serde_json::to_string(schema).unwrap()); let expected = expect![[ - r#"[{"name":"SmallInt","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Int"]},{"name":"Integer","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Int"]},{"name":"BigInt","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["BigInt"]},{"name":"Decimal","_number_of_args":0,"_number_of_optional_args":2,"prisma_types":["Decimal"]},{"name":"Money","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Decimal"]},{"name":"Inet","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"Oid","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Int"]},{"name":"Citext","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"Real","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Float"]},{"name":"DoublePrecision","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Float"]},{"name":"VarChar","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Char","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Text","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"ByteA","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Bytes"]},{"name":"Timestamp","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Timestamptz","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Date","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["DateTime"]},{"name":"Time","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Timetz","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Boolean","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Boolean"]},{"name":"Bit","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"VarBit","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Uuid","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"Xml","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"Json","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Json"]},{"name":"JsonB","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Json"]}]"# + r#"[{"name":"SmallInt","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Int"]},{"name":"Integer","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Int"]},{"name":"BigInt","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["BigInt"]},{"name":"Decimal","_number_of_args":0,"_number_of_optional_args":2,"prisma_types":["Decimal"]},{"name":"Money","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Decimal"]},{"name":"Inet","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"Oid","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Int"]},{"name":"Citext","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"Real","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Float"]},{"name":"DoublePrecision","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Float"]},{"name":"VarChar","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Char","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Text","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"ByteA","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Bytes"]},{"name":"Timestamp","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Timestamptz","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Date","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["DateTime"]},{"name":"Time","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Timetz","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Boolean","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Boolean"]},{"name":"Bit","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"VarBit","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Uuid","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"Xml","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"Json","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Json"]},{"name":"JsonB","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Json"]},{"name":"Geometry","_number_of_args":0,"_number_of_optional_args":2,"prisma_types":["Geometry","GeoJson"]},{"name":"Geography","_number_of_args":0,"_number_of_optional_args":2,"prisma_types":["Geometry","GeoJson"]}]"# ]]; expected.assert_eq(&result); } From 33048e938cab7a94c382769709528566119adc75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Tue, 1 Oct 2024 00:05:42 +0200 Subject: [PATCH 038/103] Update wasm toolchain --- query-engine/query-engine-wasm/rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/query-engine/query-engine-wasm/rust-toolchain.toml b/query-engine/query-engine-wasm/rust-toolchain.toml index 5048fd2e74a6..fab6164d265c 100644 --- a/query-engine/query-engine-wasm/rust-toolchain.toml +++ b/query-engine/query-engine-wasm/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "nightly-2024-05-25" +channel = "nightly-2024-09-29" components = ["clippy", "rustfmt", "rust-src"] targets = [ "wasm32-unknown-unknown", From 56644f3aafadfb9ac58113ae99b854f4ea170605 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Tue, 1 Oct 2024 00:06:08 +0200 Subject: [PATCH 039/103] Fix PostGIS version test --- .../tests/describers/postgres_describer_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schema-engine/sql-schema-describer/tests/describers/postgres_describer_tests.rs b/schema-engine/sql-schema-describer/tests/describers/postgres_describer_tests.rs index ba6c20be1118..3c28da38dfab 100644 --- a/schema-engine/sql-schema-describer/tests/describers/postgres_describer_tests.rs +++ b/schema-engine/sql-schema-describer/tests/describers/postgres_describer_tests.rs @@ -1290,7 +1290,7 @@ fn all_postgis_column_types_must_work(api: TestApi) { DatabaseExtension { name: "postgis", schema: "prisma-tests", - version: "3.4.2", + version: "3.4.3", relocatable: false, }, ], From a3db88e346809175b9499c5755c7e910c891ece0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Tue, 1 Oct 2024 00:06:37 +0200 Subject: [PATCH 040/103] Add Geometry handling in quaint from_type_identifier --- quaint/src/connector/column_type.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/quaint/src/connector/column_type.rs b/quaint/src/connector/column_type.rs index e379eb24eeb1..15d230082225 100644 --- a/quaint/src/connector/column_type.rs +++ b/quaint/src/connector/column_type.rs @@ -181,6 +181,8 @@ impl ColumnType { ColumnType::Numeric } else if value.is_text() { ColumnType::Text + } else if value.is_geometry() { + ColumnType::Geometry } else { ColumnType::Unknown } From a16d952f056f3e8dbdf17bf40b36bd0622917354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Tue, 1 Oct 2024 01:11:04 +0200 Subject: [PATCH 041/103] Use SRID 4326 in Sqlite introspection tests --- .../tests/native_types/sqlite.rs | 128 +++++++++--------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs b/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs index 0309a16f3aeb..87c1cb0428e2 100644 --- a/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs +++ b/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs @@ -9,38 +9,38 @@ async fn native_spatial_type_columns_feature_on(api: &mut TestApi) -> TestResult ); SELECT - AddGeometryColumn('User', 'geometry_xy', 3857, 'GEOMETRY', 'XY', 0), - AddGeometryColumn('User', 'geometry_xyz', 3857, 'GEOMETRY', 'XYZ', 0), - AddGeometryColumn('User', 'geometry_xym', 3857, 'GEOMETRY', 'XYM', 0), - AddGeometryColumn('User', 'geometry_xyzm', 3857, 'GEOMETRY', 'XYZM', 0), - AddGeometryColumn('User', 'point_xy', 3857, 'POINT', 'XY', 0), - AddGeometryColumn('User', 'point_xyz', 3857, 'POINT', 'XYZ', 0), - AddGeometryColumn('User', 'point_xym', 3857, 'POINT', 'XYM', 0), - AddGeometryColumn('User', 'point_xyzm', 3857, 'POINT', 'XYZM', 0), - AddGeometryColumn('User', 'linestring_xy', 3857, 'LINESTRING', 'XY', 0), - AddGeometryColumn('User', 'linestring_xyz', 3857, 'LINESTRING', 'XYZ', 0), - AddGeometryColumn('User', 'linestring_xym', 3857, 'LINESTRING', 'XYM', 0), - AddGeometryColumn('User', 'linestring_xyzm', 3857, 'LINESTRING', 'XYZM', 0), - AddGeometryColumn('User', 'polygon_xy', 3857, 'POLYGON', 'XY', 0), - AddGeometryColumn('User', 'polygon_xyz', 3857, 'POLYGON', 'XYZ', 0), - AddGeometryColumn('User', 'polygon_xym', 3857, 'POLYGON', 'XYM', 0), - AddGeometryColumn('User', 'polygon_xyzm', 3857, 'POLYGON', 'XYZM', 0), - AddGeometryColumn('User', 'multipoint_xy', 3857, 'MULTIPOINT', 'XY', 0), - AddGeometryColumn('User', 'multipoint_xyz', 3857, 'MULTIPOINT', 'XYZ', 0), - AddGeometryColumn('User', 'multipoint_xym', 3857, 'MULTIPOINT', 'XYM', 0), - AddGeometryColumn('User', 'multipoint_xyzm', 3857, 'MULTIPOINT', 'XYZM', 0), - AddGeometryColumn('User', 'multilinestring_xy', 3857, 'MULTILINESTRING', 'XY', 0), - AddGeometryColumn('User', 'multilinestring_xyz', 3857, 'MULTILINESTRING', 'XYZ', 0), - AddGeometryColumn('User', 'multilinestring_xym', 3857, 'MULTILINESTRING', 'XYM', 0), - AddGeometryColumn('User', 'multilinestring_xyzm', 3857, 'MULTILINESTRING', 'XYZM', 0), - AddGeometryColumn('User', 'multipolygon_xy', 3857, 'MULTIPOLYGON', 'XY', 0), - AddGeometryColumn('User', 'multipolygon_xyz', 3857, 'MULTIPOLYGON', 'XYZ', 0), - AddGeometryColumn('User', 'multipolygon_xym', 3857, 'MULTIPOLYGON', 'XYM', 0), - AddGeometryColumn('User', 'multipolygon_xyzm', 3857, 'MULTIPOLYGON', 'XYZM', 0), - AddGeometryColumn('User', 'geometrycollection_xy', 3857, 'GEOMETRYCOLLECTION', 'XY', 0), - AddGeometryColumn('User', 'geometrycollection_xyz', 3857, 'GEOMETRYCOLLECTION', 'XYZ', 0), - AddGeometryColumn('User', 'geometrycollection_xym', 3857, 'GEOMETRYCOLLECTION', 'XYM', 0), - AddGeometryColumn('User', 'geometrycollection_xyzm', 3857, 'GEOMETRYCOLLECTION', 'XYZM', 0); + AddGeometryColumn('User', 'geometry_xy', 4326, 'GEOMETRY', 'XY', 0), + AddGeometryColumn('User', 'geometry_xyz', 4326, 'GEOMETRY', 'XYZ', 0), + AddGeometryColumn('User', 'geometry_xym', 4326, 'GEOMETRY', 'XYM', 0), + AddGeometryColumn('User', 'geometry_xyzm', 4326, 'GEOMETRY', 'XYZM', 0), + AddGeometryColumn('User', 'point_xy', 4326, 'POINT', 'XY', 0), + AddGeometryColumn('User', 'point_xyz', 4326, 'POINT', 'XYZ', 0), + AddGeometryColumn('User', 'point_xym', 4326, 'POINT', 'XYM', 0), + AddGeometryColumn('User', 'point_xyzm', 4326, 'POINT', 'XYZM', 0), + AddGeometryColumn('User', 'linestring_xy', 4326, 'LINESTRING', 'XY', 0), + AddGeometryColumn('User', 'linestring_xyz', 4326, 'LINESTRING', 'XYZ', 0), + AddGeometryColumn('User', 'linestring_xym', 4326, 'LINESTRING', 'XYM', 0), + AddGeometryColumn('User', 'linestring_xyzm', 4326, 'LINESTRING', 'XYZM', 0), + AddGeometryColumn('User', 'polygon_xy', 4326, 'POLYGON', 'XY', 0), + AddGeometryColumn('User', 'polygon_xyz', 4326, 'POLYGON', 'XYZ', 0), + AddGeometryColumn('User', 'polygon_xym', 4326, 'POLYGON', 'XYM', 0), + AddGeometryColumn('User', 'polygon_xyzm', 4326, 'POLYGON', 'XYZM', 0), + AddGeometryColumn('User', 'multipoint_xy', 4326, 'MULTIPOINT', 'XY', 0), + AddGeometryColumn('User', 'multipoint_xyz', 4326, 'MULTIPOINT', 'XYZ', 0), + AddGeometryColumn('User', 'multipoint_xym', 4326, 'MULTIPOINT', 'XYM', 0), + AddGeometryColumn('User', 'multipoint_xyzm', 4326, 'MULTIPOINT', 'XYZM', 0), + AddGeometryColumn('User', 'multilinestring_xy', 4326, 'MULTILINESTRING', 'XY', 0), + AddGeometryColumn('User', 'multilinestring_xyz', 4326, 'MULTILINESTRING', 'XYZ', 0), + AddGeometryColumn('User', 'multilinestring_xym', 4326, 'MULTILINESTRING', 'XYM', 0), + AddGeometryColumn('User', 'multilinestring_xyzm', 4326, 'MULTILINESTRING', 'XYZM', 0), + AddGeometryColumn('User', 'multipolygon_xy', 4326, 'MULTIPOLYGON', 'XY', 0), + AddGeometryColumn('User', 'multipolygon_xyz', 4326, 'MULTIPOLYGON', 'XYZ', 0), + AddGeometryColumn('User', 'multipolygon_xym', 4326, 'MULTIPOLYGON', 'XYM', 0), + AddGeometryColumn('User', 'multipolygon_xyzm', 4326, 'MULTIPOLYGON', 'XYZM', 0), + AddGeometryColumn('User', 'geometrycollection_xy', 4326, 'GEOMETRYCOLLECTION', 'XY', 0), + AddGeometryColumn('User', 'geometrycollection_xyz', 4326, 'GEOMETRYCOLLECTION', 'XYZ', 0), + AddGeometryColumn('User', 'geometrycollection_xym', 4326, 'GEOMETRYCOLLECTION', 'XYM', 0), + AddGeometryColumn('User', 'geometrycollection_xyzm', 4326, 'GEOMETRYCOLLECTION', 'XYZM', 0); "#}; api.raw_cmd(setup).await; @@ -48,38 +48,38 @@ async fn native_spatial_type_columns_feature_on(api: &mut TestApi) -> TestResult let expectation = expect![[r#" model User { id Int @id @default(autoincrement()) - geometry_xy Geometry? @db.Geometry(Geometry, 3857) - geometry_xyz Geometry? @db.Geometry(GeometryZ, 3857) - geometry_xym Geometry? @db.Geometry(GeometryM, 3857) - geometry_xyzm Geometry? @db.Geometry(GeometryZM, 3857) - point_xy Geometry? @db.Geometry(Point, 3857) - point_xyz Geometry? @db.Geometry(PointZ, 3857) - point_xym Geometry? @db.Geometry(PointM, 3857) - point_xyzm Geometry? @db.Geometry(PointZM, 3857) - linestring_xy Geometry? @db.Geometry(LineString, 3857) - linestring_xyz Geometry? @db.Geometry(LineStringZ, 3857) - linestring_xym Geometry? @db.Geometry(LineStringM, 3857) - linestring_xyzm Geometry? @db.Geometry(LineStringZM, 3857) - polygon_xy Geometry? @db.Geometry(Polygon, 3857) - polygon_xyz Geometry? @db.Geometry(PolygonZ, 3857) - polygon_xym Geometry? @db.Geometry(PolygonM, 3857) - polygon_xyzm Geometry? @db.Geometry(PolygonZM, 3857) - multipoint_xy Geometry? @db.Geometry(MultiPoint, 3857) - multipoint_xyz Geometry? @db.Geometry(MultiPointZ, 3857) - multipoint_xym Geometry? @db.Geometry(MultiPointM, 3857) - multipoint_xyzm Geometry? @db.Geometry(MultiPointZM, 3857) - multilinestring_xy Geometry? @db.Geometry(MultiLineString, 3857) - multilinestring_xyz Geometry? @db.Geometry(MultiLineStringZ, 3857) - multilinestring_xym Geometry? @db.Geometry(MultiLineStringM, 3857) - multilinestring_xyzm Geometry? @db.Geometry(MultiLineStringZM, 3857) - multipolygon_xy Geometry? @db.Geometry(MultiPolygon, 3857) - multipolygon_xyz Geometry? @db.Geometry(MultiPolygonZ, 3857) - multipolygon_xym Geometry? @db.Geometry(MultiPolygonM, 3857) - multipolygon_xyzm Geometry? @db.Geometry(MultiPolygonZM, 3857) - geometrycollection_xy Geometry? @db.Geometry(GeometryCollection, 3857) - geometrycollection_xyz Geometry? @db.Geometry(GeometryCollectionZ, 3857) - geometrycollection_xym Geometry? @db.Geometry(GeometryCollectionM, 3857) - geometrycollection_xyzm Geometry? @db.Geometry(GeometryCollectionZM, 3857) + geometry_xy Geometry? @db.Geometry(Geometry, 4326) + geometry_xyz Geometry? @db.Geometry(GeometryZ, 4326) + geometry_xym Geometry? @db.Geometry(GeometryM, 4326) + geometry_xyzm Geometry? @db.Geometry(GeometryZM, 4326) + point_xy Geometry? @db.Geometry(Point, 4326) + point_xyz Geometry? @db.Geometry(PointZ, 4326) + point_xym Geometry? @db.Geometry(PointM, 4326) + point_xyzm Geometry? @db.Geometry(PointZM, 4326) + linestring_xy Geometry? @db.Geometry(LineString, 4326) + linestring_xyz Geometry? @db.Geometry(LineStringZ, 4326) + linestring_xym Geometry? @db.Geometry(LineStringM, 4326) + linestring_xyzm Geometry? @db.Geometry(LineStringZM, 4326) + polygon_xy Geometry? @db.Geometry(Polygon, 4326) + polygon_xyz Geometry? @db.Geometry(PolygonZ, 4326) + polygon_xym Geometry? @db.Geometry(PolygonM, 4326) + polygon_xyzm Geometry? @db.Geometry(PolygonZM, 4326) + multipoint_xy Geometry? @db.Geometry(MultiPoint, 4326) + multipoint_xyz Geometry? @db.Geometry(MultiPointZ, 4326) + multipoint_xym Geometry? @db.Geometry(MultiPointM, 4326) + multipoint_xyzm Geometry? @db.Geometry(MultiPointZM, 4326) + multilinestring_xy Geometry? @db.Geometry(MultiLineString, 4326) + multilinestring_xyz Geometry? @db.Geometry(MultiLineStringZ, 4326) + multilinestring_xym Geometry? @db.Geometry(MultiLineStringM, 4326) + multilinestring_xyzm Geometry? @db.Geometry(MultiLineStringZM, 4326) + multipolygon_xy Geometry? @db.Geometry(MultiPolygon, 4326) + multipolygon_xyz Geometry? @db.Geometry(MultiPolygonZ, 4326) + multipolygon_xym Geometry? @db.Geometry(MultiPolygonM, 4326) + multipolygon_xyzm Geometry? @db.Geometry(MultiPolygonZM, 4326) + geometrycollection_xy Geometry? @db.Geometry(GeometryCollection, 4326) + geometrycollection_xyz Geometry? @db.Geometry(GeometryCollectionZ, 4326) + geometrycollection_xym Geometry? @db.Geometry(GeometryCollectionM, 4326) + geometrycollection_xyzm Geometry? @db.Geometry(GeometryCollectionZM, 4326) } "#]]; From ff3e9aa6bee36e28e9337280fb3f79e7cfd62bdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Tue, 1 Oct 2024 01:30:22 +0200 Subject: [PATCH 042/103] Update test unknown_type_mysql --- .../query-engine-tests/tests/raw/sql/typed_output.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/raw/sql/typed_output.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/raw/sql/typed_output.rs index 980392054bfd..4ab5884cd460 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/raw/sql/typed_output.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/raw/sql/typed_output.rs @@ -441,10 +441,10 @@ mod typed_output { } #[connector_test(schema(generic), only(Mysql))] - async fn unknown_type_mysql(runner: Runner) -> TestResult<()> { + async fn geometry_type_mysql(runner: Runner) -> TestResult<()> { insta::assert_snapshot!( run_query!(&runner, fmt_query_raw(r#"SELECT POINT(1, 1);"#, vec![])), - @r###"{"data":{"queryRaw":{"columns":["POINT(1, 1)"],"types":["bytes"],"rows":[["AAAAAAEBAAAAAAAAAAAA8D8AAAAAAADwPw=="]]}}}"### + @r###"{"data":{"queryRaw":{"columns":["POINT(1, 1)"],"types":["geometry"],"rows":[["POINT(1 1)"]}}}"### ); Ok(()) From 9f205edb71f8f82d3bbd291bcf995d3623617b4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Tue, 1 Oct 2024 01:45:39 +0200 Subject: [PATCH 043/103] Add GeoJson handling in MongoDB into_bson --- .../connectors/mongodb-query-connector/src/value.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/query-engine/connectors/mongodb-query-connector/src/value.rs b/query-engine/connectors/mongodb-query-connector/src/value.rs index 58533cee4120..7c8a675818d9 100644 --- a/query-engine/connectors/mongodb-query-connector/src/value.rs +++ b/query-engine/connectors/mongodb-query-connector/src/value.rs @@ -199,6 +199,16 @@ impl IntoBson for (&MongoDbType, PrismaValue) { })? } + // Geometry + (MongoDbType::Json, PrismaValue::GeoJson(json)) => { + let val: Value = serde_json::from_str(&json)?; + + Bson::try_from(val).map_err(|_| MongoError::ConversionError { + from: "Stringified GeoJSON".to_owned(), + to: "Mongo BSON (extJSON)".to_owned(), + })? + } + // Unhandled conversions (mdb_type, p_val) => { return Err(MongoError::ConversionError { @@ -271,7 +281,7 @@ impl IntoBson for (&TypeIdentifier, PrismaValue) { (TypeIdentifier::Geometry(GeometryFormat::GeoJSON), PrismaValue::GeoJson(json)) => { let val: Value = serde_json::from_str(&json)?; Bson::try_from(val).map_err(|_| MongoError::ConversionError { - from: "Stringified JSON".to_owned(), + from: "Stringified GeoJSON".to_owned(), to: "Mongo BSON (extJSON)".to_owned(), })? } From 7d6d9603adb42c7048e630d358c1cf604839bf55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Tue, 1 Oct 2024 01:56:21 +0200 Subject: [PATCH 044/103] Fix geometry_type_mysql --- .../query-engine-tests/tests/raw/sql/typed_output.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/raw/sql/typed_output.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/raw/sql/typed_output.rs index 4ab5884cd460..6edda2a7d396 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/raw/sql/typed_output.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/raw/sql/typed_output.rs @@ -444,7 +444,7 @@ mod typed_output { async fn geometry_type_mysql(runner: Runner) -> TestResult<()> { insta::assert_snapshot!( run_query!(&runner, fmt_query_raw(r#"SELECT POINT(1, 1);"#, vec![])), - @r###"{"data":{"queryRaw":{"columns":["POINT(1, 1)"],"types":["geometry"],"rows":[["POINT(1 1)"]}}}"### + @r###"{"data":{"queryRaw":{"columns":["POINT(1, 1)"],"types":["geometry"],"rows":[["POINT(1 1)"]]}}}"### ); Ok(()) From 2b35a946bee4b585af1e424f8bdee1cea20bcc57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Tue, 1 Oct 2024 02:09:16 +0200 Subject: [PATCH 045/103] Use SRID 4326 in spatialite describer tests --- .../describers/sqlite_describer_tests.rs | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/schema-engine/sql-schema-describer/tests/describers/sqlite_describer_tests.rs b/schema-engine/sql-schema-describer/tests/describers/sqlite_describer_tests.rs index f75d7df8803c..05619cc3b71a 100644 --- a/schema-engine/sql-schema-describer/tests/describers/sqlite_describer_tests.rs +++ b/schema-engine/sql-schema-describer/tests/describers/sqlite_describer_tests.rs @@ -219,38 +219,38 @@ fn spatialite_column_types_must_work(api: TestApi) { ); SELECT - AddGeometryColumn('User', 'geometry_xy', 3857, 'GEOMETRY', 'XY', 0), - AddGeometryColumn('User', 'geometry_xyz', 3857, 'GEOMETRY', 'XYZ', 0), - AddGeometryColumn('User', 'geometry_xym', 3857, 'GEOMETRY', 'XYM', 0), - AddGeometryColumn('User', 'geometry_xyzm', 3857, 'GEOMETRY', 'XYZM', 0), - AddGeometryColumn('User', 'point_xy', 3857, 'POINT', 'XY', 0), - AddGeometryColumn('User', 'point_xyz', 3857, 'POINT', 'XYZ', 0), - AddGeometryColumn('User', 'point_xym', 3857, 'POINT', 'XYM', 0), - AddGeometryColumn('User', 'point_xyzm', 3857, 'POINT', 'XYZM', 0), - AddGeometryColumn('User', 'linestring_xy', 3857, 'LINESTRING', 'XY', 0), - AddGeometryColumn('User', 'linestring_xyz', 3857, 'LINESTRING', 'XYZ', 0), - AddGeometryColumn('User', 'linestring_xym', 3857, 'LINESTRING', 'XYM', 0), - AddGeometryColumn('User', 'linestring_xyzm', 3857, 'LINESTRING', 'XYZM', 0), - AddGeometryColumn('User', 'polygon_xy', 3857, 'POLYGON', 'XY', 0), - AddGeometryColumn('User', 'polygon_xyz', 3857, 'POLYGON', 'XYZ', 0), - AddGeometryColumn('User', 'polygon_xym', 3857, 'POLYGON', 'XYM', 0), - AddGeometryColumn('User', 'polygon_xyzm', 3857, 'POLYGON', 'XYZM', 0), - AddGeometryColumn('User', 'multipoint_xy', 3857, 'MULTIPOINT', 'XY', 0), - AddGeometryColumn('User', 'multipoint_xyz', 3857, 'MULTIPOINT', 'XYZ', 0), - AddGeometryColumn('User', 'multipoint_xym', 3857, 'MULTIPOINT', 'XYM', 0), - AddGeometryColumn('User', 'multipoint_xyzm', 3857, 'MULTIPOINT', 'XYZM', 0), - AddGeometryColumn('User', 'multilinestring_xy', 3857, 'MULTILINESTRING', 'XY', 0), - AddGeometryColumn('User', 'multilinestring_xyz', 3857, 'MULTILINESTRING', 'XYZ', 0), - AddGeometryColumn('User', 'multilinestring_xym', 3857, 'MULTILINESTRING', 'XYM', 0), - AddGeometryColumn('User', 'multilinestring_xyzm', 3857, 'MULTILINESTRING', 'XYZM', 0), - AddGeometryColumn('User', 'multipolygon_xy', 3857, 'MULTIPOLYGON', 'XY', 0), - AddGeometryColumn('User', 'multipolygon_xyz', 3857, 'MULTIPOLYGON', 'XYZ', 0), - AddGeometryColumn('User', 'multipolygon_xym', 3857, 'MULTIPOLYGON', 'XYM', 0), - AddGeometryColumn('User', 'multipolygon_xyzm', 3857, 'MULTIPOLYGON', 'XYZM', 0), - AddGeometryColumn('User', 'geometrycollection_xy', 3857, 'GEOMETRYCOLLECTION', 'XY', 0), - AddGeometryColumn('User', 'geometrycollection_xyz', 3857, 'GEOMETRYCOLLECTION', 'XYZ', 0), - AddGeometryColumn('User', 'geometrycollection_xym', 3857, 'GEOMETRYCOLLECTION', 'XYM', 0), - AddGeometryColumn('User', 'geometrycollection_xyzm', 3857, 'GEOMETRYCOLLECTION', 'XYZM', 0); + AddGeometryColumn('User', 'geometry_xy', 4326, 'GEOMETRY', 'XY', 0), + AddGeometryColumn('User', 'geometry_xyz', 4326, 'GEOMETRY', 'XYZ', 0), + AddGeometryColumn('User', 'geometry_xym', 4326, 'GEOMETRY', 'XYM', 0), + AddGeometryColumn('User', 'geometry_xyzm', 4326, 'GEOMETRY', 'XYZM', 0), + AddGeometryColumn('User', 'point_xy', 4326, 'POINT', 'XY', 0), + AddGeometryColumn('User', 'point_xyz', 4326, 'POINT', 'XYZ', 0), + AddGeometryColumn('User', 'point_xym', 4326, 'POINT', 'XYM', 0), + AddGeometryColumn('User', 'point_xyzm', 4326, 'POINT', 'XYZM', 0), + AddGeometryColumn('User', 'linestring_xy', 4326, 'LINESTRING', 'XY', 0), + AddGeometryColumn('User', 'linestring_xyz', 4326, 'LINESTRING', 'XYZ', 0), + AddGeometryColumn('User', 'linestring_xym', 4326, 'LINESTRING', 'XYM', 0), + AddGeometryColumn('User', 'linestring_xyzm', 4326, 'LINESTRING', 'XYZM', 0), + AddGeometryColumn('User', 'polygon_xy', 4326, 'POLYGON', 'XY', 0), + AddGeometryColumn('User', 'polygon_xyz', 4326, 'POLYGON', 'XYZ', 0), + AddGeometryColumn('User', 'polygon_xym', 4326, 'POLYGON', 'XYM', 0), + AddGeometryColumn('User', 'polygon_xyzm', 4326, 'POLYGON', 'XYZM', 0), + AddGeometryColumn('User', 'multipoint_xy', 4326, 'MULTIPOINT', 'XY', 0), + AddGeometryColumn('User', 'multipoint_xyz', 4326, 'MULTIPOINT', 'XYZ', 0), + AddGeometryColumn('User', 'multipoint_xym', 4326, 'MULTIPOINT', 'XYM', 0), + AddGeometryColumn('User', 'multipoint_xyzm', 4326, 'MULTIPOINT', 'XYZM', 0), + AddGeometryColumn('User', 'multilinestring_xy', 4326, 'MULTILINESTRING', 'XY', 0), + AddGeometryColumn('User', 'multilinestring_xyz', 4326, 'MULTILINESTRING', 'XYZ', 0), + AddGeometryColumn('User', 'multilinestring_xym', 4326, 'MULTILINESTRING', 'XYM', 0), + AddGeometryColumn('User', 'multilinestring_xyzm', 4326, 'MULTILINESTRING', 'XYZM', 0), + AddGeometryColumn('User', 'multipolygon_xy', 4326, 'MULTIPOLYGON', 'XY', 0), + AddGeometryColumn('User', 'multipolygon_xyz', 4326, 'MULTIPOLYGON', 'XYZ', 0), + AddGeometryColumn('User', 'multipolygon_xym', 4326, 'MULTIPOLYGON', 'XYM', 0), + AddGeometryColumn('User', 'multipolygon_xyzm', 4326, 'MULTIPOLYGON', 'XYZM', 0), + AddGeometryColumn('User', 'geometrycollection_xy', 4326, 'GEOMETRYCOLLECTION', 'XY', 0), + AddGeometryColumn('User', 'geometrycollection_xyz', 4326, 'GEOMETRYCOLLECTION', 'XYZ', 0), + AddGeometryColumn('User', 'geometrycollection_xym', 4326, 'GEOMETRYCOLLECTION', 'XYM', 0), + AddGeometryColumn('User', 'geometrycollection_xyzm', 4326, 'GEOMETRYCOLLECTION', 'XYZM', 0); "#; api.raw_cmd(sql); let expectation = expect![[r#" From fffdaccc12efd4a458de408f179f47d3fa68bd53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Tue, 1 Oct 2024 02:48:01 +0200 Subject: [PATCH 046/103] Add cfd1 and libsql.js.wasm to spatialite tests exclude list --- .../tests/queries/filters/geometry_filter.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs index f0442f889812..c60f8d0ce316 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs @@ -101,12 +101,12 @@ mod geometry_filter_spec { Ok(()) } - #[connector_test(schema(schema), exclude(Postgres, Sqlite(3, "libsql.js")))] + #[connector_test(schema(schema), exclude(Postgres, Sqlite(3, "cfd1", "libsql.js", "libsql.js.wasm")))] async fn basic_where(runner: Runner) -> TestResult<()> { basic_where_test(runner).await } - #[connector_test(schema(schema), exclude(Postgres, Sqlite(3, "libsql.js")))] + #[connector_test(schema(schema), exclude(Postgres, Sqlite(3, "cfd1", "libsql.js", "libsql.js.wasm")))] async fn where_shorthands(runner: Runner) -> TestResult<()> { where_shorthands_test(runner).await } @@ -115,7 +115,7 @@ mod geometry_filter_spec { // see discussion here: https://github.com/prisma/prisma-engines/pull/4208#issuecomment-1828997865 #[connector_test( schema(schema), - exclude(Postgres, Sqlite(3, "libsql.js"), MySQL("mariadb")), + exclude(Postgres, Sqlite(3, "cfd1", "libsql.js", "libsql.js.wasm"), MySQL("mariadb")), capabilities(GeometryFiltering) )] async fn geometric_comparison_filters(runner: Runner) -> TestResult<()> { From 0c912c0fc8385f167393d89283bebcf9e20fa13b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Tue, 1 Oct 2024 09:56:48 +0200 Subject: [PATCH 047/103] Add cfd1 and libsql.js.wasm to other spatialite tests exclude list --- .../tests/writes/top_level_mutations/create.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs index dafae1cec5c9..9ac52a0e8e0d 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs @@ -475,7 +475,7 @@ mod geometry_create { schema.to_owned() } - #[connector_test(schema(geometry_opt), exclude(Postgres, Sqlite(3, "libsql.js")))] + #[connector_test(schema(geometry_opt), exclude(Postgres, Sqlite(3, "cfd1", "libsql.js", "libsql.js.wasm")))] async fn create_geometry(runner: Runner) -> TestResult<()> { create_geometry_test(runner).await } From 906f13793809ea2206941ed0e7f6a869f3a6f91b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Wed, 2 Oct 2024 14:56:25 +0200 Subject: [PATCH 048/103] Change GeoJson default SRID to 0 for PostGIS/Spatialite --- .../cockroach_datamodel_connector.rs | 38 +++-- .../src/builtin_connectors/geometry.rs | 36 ++++- .../mysql_datamodel_connector.rs | 4 +- .../postgres_datamodel_connector.rs | 10 +- .../sqlite_datamodel_connector.rs | 16 +- .../tests/types/cockroachdb_native_types.rs | 144 +++++++++--------- .../writes/top_level_mutations/create.rs | 5 +- .../src/model_extensions/scalar_field.rs | 21 ++- .../connectors/sql-query-connector/src/row.rs | 4 +- .../src/sql_renderer/sqlite_renderer.rs | 2 +- 10 files changed, 168 insertions(+), 112 deletions(-) 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 79b6f7b4ebb7..1394361af914 100644 --- a/psl/psl-core/src/builtin_connectors/cockroach_datamodel_connector.rs +++ b/psl/psl-core/src/builtin_connectors/cockroach_datamodel_connector.rs @@ -96,7 +96,7 @@ const SCALAR_TYPE_DEFAULTS: &[(ScalarType, CockroachType)] = &[ ScalarType::GeoJson, CockroachType::Geometry(Some(GeometryParams { type_: GeometryType::Geometry, - srid: 4326, + srid: 0, })), ), ]; @@ -220,19 +220,6 @@ impl Connector for CockroachDatamodelConnector { CockroachType::Bit(Some(0)) | CockroachType::VarBit(Some(0)) => { errors.push_error(error.new_argument_m_out_of_range_error("M must be a positive integer.", span)) } - CockroachType::Geometry(Some(g)) | CockroachType::Geography(Some(g)) - if *scalar_type == ScalarType::GeoJson && g.srid != 4326 => - { - errors.push_error(error.new_argument_m_out_of_range_error("GeoJson SRID must be 4326.", span)) - } - CockroachType::Geometry(Some(g)) | CockroachType::Geography(Some(g)) if g.srid < 0 || g.srid > 999000 => { - errors.push_error(error.new_argument_m_out_of_range_error("SRID must be between 0 and 999000.", span)) - } - CockroachType::Geometry(Some(g)) | CockroachType::Geography(Some(g)) if g.type_.is_extra() => errors - .push_error(error.new_argument_m_out_of_range_error( - &format!("{} isn't supported for the current connector.", g.type_), - span, - )), CockroachType::Timestamp(Some(p)) | CockroachType::Timestamptz(Some(p)) | CockroachType::Time(Some(p)) @@ -241,6 +228,29 @@ impl Connector for CockroachDatamodelConnector { { errors.push_error(error.new_argument_m_out_of_range_error("M can range from 0 to 6.", span)) } + CockroachType::Geometry(Some(g)) | CockroachType::Geography(Some(g)) if g.type_.is_extended() => errors + .push_error(error.new_argument_m_out_of_range_error( + &format!("{} isn't supported for the current connector.", g.type_), + span, + )), + CockroachType::Geometry(Some(g)) | CockroachType::Geography(Some(g)) + if *scalar_type == ScalarType::GeoJson && !g.type_.is_geojson_compatible() => + { + errors.push_error( + error.new_argument_m_out_of_range_error( + &format!("{} isn't compatible with GeoJson.", g.type_), + span, + ), + ) + } + CockroachType::Geometry(Some(g)) | CockroachType::Geography(Some(g)) + if *scalar_type == ScalarType::GeoJson && !matches!(g.srid, 0 | 4326) => + { + errors.push_error(error.new_argument_m_out_of_range_error("GeoJson SRID must be 4326.", span)) + } + CockroachType::Geometry(Some(g)) | CockroachType::Geography(Some(g)) if g.srid < 0 || g.srid > 999000 => { + errors.push_error(error.new_argument_m_out_of_range_error("SRID must be between 0 and 999000.", span)) + } _ => (), } } diff --git a/psl/psl-core/src/builtin_connectors/geometry.rs b/psl/psl-core/src/builtin_connectors/geometry.rs index 0b9920bb884f..177280b68172 100644 --- a/psl/psl-core/src/builtin_connectors/geometry.rs +++ b/psl/psl-core/src/builtin_connectors/geometry.rs @@ -84,21 +84,45 @@ pub enum GeometryType { TriangleZM = 3017, } +#[derive(Debug, Default, Clone, Copy, PartialEq, PartialOrd)] +pub enum GeometryDimension { + #[default] + XY, + XYZ, + XYM, + XYZM, +} + +impl fmt::Display for GeometryDimension { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::XY => write!(f, "XY"), + Self::XYZ => write!(f, "XYZ"), + Self::XYM => write!(f, "XYM"), + Self::XYZM => write!(f, "XYZM"), + } + } +} + impl GeometryType { - pub fn is_extra(&self) -> bool { + pub fn is_extended(&self) -> bool { self.as_2d() > Self::GeometryCollection } + pub fn is_geojson_compatible(&self) -> bool { + !self.is_extended() && self.dimension() <= &GeometryDimension::XYZ + } + pub fn as_2d(&self) -> Self { Self::try_from(*self as u32 % 1000).unwrap() } - pub fn dimensions(&self) -> &'static str { + pub fn dimension(&self) -> &'static GeometryDimension { match *self as u32 / 1000 { - 0 => "XY", - 1 => "XYZ", - 2 => "XYM", - 3 => "XYZM", + 0 => &GeometryDimension::XY, + 1 => &GeometryDimension::XYZ, + 2 => &GeometryDimension::XYM, + 3 => &GeometryDimension::XYZM, _ => unreachable!(), } } diff --git a/psl/psl-core/src/builtin_connectors/mysql_datamodel_connector.rs b/psl/psl-core/src/builtin_connectors/mysql_datamodel_connector.rs index dd2f6edf923e..d5b6e8d6b2e9 100644 --- a/psl/psl-core/src/builtin_connectors/mysql_datamodel_connector.rs +++ b/psl/psl-core/src/builtin_connectors/mysql_datamodel_connector.rs @@ -91,7 +91,6 @@ const SCALAR_TYPE_DEFAULTS: &[(ScalarType, MySqlType)] = &[ (ScalarType::Bytes, MySqlType::LongBlob), (ScalarType::Json, MySqlType::Json), (ScalarType::Geometry, MySqlType::Geometry(None)), - // TODO@geometry In MYSQL8+, ideally we'd set the default SRID to 4326 (ScalarType::GeoJson, MySqlType::Geometry(None)), ]; @@ -241,9 +240,8 @@ impl Connector for MySqlDatamodelConnector { | MultiLineString(Some(srid)) | MultiPolygon(Some(srid)) | GeometryCollection(Some(srid)) - if *scalar_type == ScalarType::GeoJson && *srid != 4326 => + if *scalar_type == ScalarType::GeoJson && !matches!(*srid, 0 | 4326) => { - // TODO@geometry MySQL <8 doesn't support SRID parameter, is there a way to catch this here ? errors.push_error(error.new_argument_m_out_of_range_error("GeoJson SRID must be 4326.", span)) } Bit(n) if *n > 1 && matches!(scalar_type, ScalarType::Boolean) => { diff --git a/psl/psl-core/src/builtin_connectors/postgres_datamodel_connector.rs b/psl/psl-core/src/builtin_connectors/postgres_datamodel_connector.rs index a4fd15fe020a..6f37d3dd76a1 100644 --- a/psl/psl-core/src/builtin_connectors/postgres_datamodel_connector.rs +++ b/psl/psl-core/src/builtin_connectors/postgres_datamodel_connector.rs @@ -107,7 +107,7 @@ const SCALAR_TYPE_DEFAULTS: &[(ScalarType, PostgresType)] = &[ ScalarType::GeoJson, PostgresType::Geometry(Some(GeometryParams { type_: GeometryType::Geometry, - srid: 4326, + srid: 0, })), ), ]; @@ -408,7 +408,9 @@ impl Connector for PostgresDatamodelConnector { Timestamp(Some(p)) | Timestamptz(Some(p)) | Time(Some(p)) | Timetz(Some(p)) if *p > 6 => { errors.push_error(error.new_argument_m_out_of_range_error("M can range from 0 to 6.", span)) } - Geometry(Some(g)) | Geography(Some(g)) if *scalar_type == ScalarType::GeoJson && g.type_.is_extra() => { + Geometry(Some(g)) | Geography(Some(g)) + if *scalar_type == ScalarType::GeoJson && !g.type_.is_geojson_compatible() => + { errors.push_error( error.new_argument_m_out_of_range_error( &format!("{} isn't compatible with GeoJson.", g.type_), @@ -416,7 +418,9 @@ impl Connector for PostgresDatamodelConnector { ), ) } - Geometry(Some(g)) | Geography(Some(g)) if *scalar_type == ScalarType::GeoJson && g.srid != 4326 => { + Geometry(Some(g)) | Geography(Some(g)) + if *scalar_type == ScalarType::GeoJson && !matches!(g.srid, 0 | 4326) => + { errors.push_error(error.new_argument_m_out_of_range_error("GeoJson SRID must be 4326.", span)) } Geometry(Some(g)) | Geography(Some(g)) if g.srid < 0 || g.srid > 999000 => { diff --git a/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs b/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs index bb222dc50768..52d3bb5155b0 100644 --- a/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs +++ b/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs @@ -54,7 +54,7 @@ const SCALAR_TYPE_DEFAULTS: &[(ScalarType, SQLiteType)] = &[ ScalarType::GeoJson, SQLiteType::Geometry(Some(GeometryParams { type_: GeometryType::Geometry, - srid: 4326, + srid: 0, })), ), ]; @@ -129,12 +129,22 @@ impl Connector for SqliteDatamodelConnector { let error = self.native_instance_error(native_type_instance); match native_type { - SQLiteType::Geometry(Some(g)) if *scalar_type == ScalarType::GeoJson && g.srid != 4326 => { + SQLiteType::Geometry(Some(g)) + if *scalar_type == ScalarType::GeoJson && !g.type_.is_geojson_compatible() => + { + errors.push_error( + error.new_argument_m_out_of_range_error( + &format!("{} isn't compatible with GeoJson.", g.type_), + span, + ), + ) + } + SQLiteType::Geometry(Some(g)) if *scalar_type == ScalarType::GeoJson && !matches!(g.srid, 0 | 4326) => { errors.push_error(error.new_argument_m_out_of_range_error("GeoJson SRID must be 4326.", span)) } SQLiteType::Geometry(Some(g)) if g.srid < -1 => errors .push_error(error.new_argument_m_out_of_range_error("SRID must be superior or equal to -1.", span)), - SQLiteType::Geometry(Some(g)) if g.type_.is_extra() => { + SQLiteType::Geometry(Some(g)) if g.type_.is_extended() => { errors.push_error(error.new_argument_m_out_of_range_error( &format!("{} isn't supported for the current connector.", g.type_), span, diff --git a/psl/psl/tests/types/cockroachdb_native_types.rs b/psl/psl/tests/types/cockroachdb_native_types.rs index 98e6b4c352d9..8466b420107e 100644 --- a/psl/psl/tests/types/cockroachdb_native_types.rs +++ b/psl/psl/tests/types/cockroachdb_native_types.rs @@ -184,78 +184,78 @@ fn cockroach_specific_native_types_are_valid() { timesttzcol DateTime @db.Timestamptz uuidcol String @db.Uuid varbitcol String @db.VarBit(200) - geomcol1 GeoJson @db.Geometry(Geometry, 4326) - geomcol2 GeoJson @db.Geometry(GeometryZ, 4326) - geomcol3 GeoJson @db.Geometry(GeometryM, 4326) - geomcol4 GeoJson @db.Geometry(GeometryZM, 4326) - geomcol5 GeoJson @db.Geometry(Point, 4326) - geomcol6 GeoJson @db.Geometry(PointZ, 4326) - geomcol7 GeoJson @db.Geometry(PointM, 4326) - geomcol8 GeoJson @db.Geometry(PointZM, 4326) - geomcol9 GeoJson @db.Geometry(Point, 4326) - geomcol10 GeoJson @db.Geometry(PointZ, 4326) - geomcol11 GeoJson @db.Geometry(PointM, 4326) - geomcol12 GeoJson @db.Geometry(PointZM, 4326) - geomcol13 GeoJson @db.Geometry(LineString, 4326) - geomcol14 GeoJson @db.Geometry(LineStringZ, 4326) - geomcol15 GeoJson @db.Geometry(LineStringM, 4326) - geomcol16 GeoJson @db.Geometry(LineStringZM, 4326) - geomcol17 GeoJson @db.Geometry(Polygon, 4326) - geomcol18 GeoJson @db.Geometry(PolygonZ, 4326) - geomcol19 GeoJson @db.Geometry(PolygonM, 4326) - geomcol20 GeoJson @db.Geometry(PolygonZM, 4326) - geomcol21 GeoJson @db.Geometry(MultiPoint, 4326) - geomcol22 GeoJson @db.Geometry(MultiPointZ, 4326) - geomcol23 GeoJson @db.Geometry(MultiPointM, 4326) - geomcol24 GeoJson @db.Geometry(MultiPointZM, 4326) - geomcol25 GeoJson @db.Geometry(MultiLineString, 4326) - geomcol26 GeoJson @db.Geometry(MultiLineStringZ, 4326) - geomcol27 GeoJson @db.Geometry(MultiLineStringM, 4326) - geomcol28 GeoJson @db.Geometry(MultiLineStringZM, 4326) - geomcol29 GeoJson @db.Geometry(MultiPolygon, 4326) - geomcol30 GeoJson @db.Geometry(MultiPolygonZ, 4326) - geomcol31 GeoJson @db.Geometry(MultiPolygonM, 4326) - geomcol32 GeoJson @db.Geometry(MultiPolygonZM, 4326) - geomcol33 GeoJson @db.Geometry(GeometryCollection, 4326) - geomcol34 GeoJson @db.Geometry(GeometryCollectionZ, 4326) - geomcol35 GeoJson @db.Geometry(GeometryCollectionM, 4326) - geomcol36 GeoJson @db.Geometry(GeometryCollectionZM, 4326) - geogcol1 GeoJson @db.Geography(Geometry, 4326) - geogcol2 GeoJson @db.Geography(GeometryZ, 4326) - geogcol3 GeoJson @db.Geography(GeometryM, 4326) - geogcol4 GeoJson @db.Geography(GeometryZM, 4326) - geogcol5 GeoJson @db.Geography(Point, 4326) - geogcol6 GeoJson @db.Geography(PointZ, 4326) - geogcol7 GeoJson @db.Geography(PointM, 4326) - geogcol8 GeoJson @db.Geography(PointZM, 4326) - geogcol9 GeoJson @db.Geography(Point, 4326) - geogcol10 GeoJson @db.Geography(PointZ, 4326) - geogcol11 GeoJson @db.Geography(PointM, 4326) - geogcol12 GeoJson @db.Geography(PointZM, 4326) - geogcol13 GeoJson @db.Geography(LineString, 4326) - geogcol14 GeoJson @db.Geography(LineStringZ, 4326) - geogcol15 GeoJson @db.Geography(LineStringM, 4326) - geogcol16 GeoJson @db.Geography(LineStringZM, 4326) - geogcol17 GeoJson @db.Geography(Polygon, 4326) - geogcol18 GeoJson @db.Geography(PolygonZ, 4326) - geogcol19 GeoJson @db.Geography(PolygonM, 4326) - geogcol20 GeoJson @db.Geography(PolygonZM, 4326) - geogcol21 GeoJson @db.Geography(MultiPoint, 4326) - geogcol22 GeoJson @db.Geography(MultiPointZ, 4326) - geogcol23 GeoJson @db.Geography(MultiPointM, 4326) - geogcol24 GeoJson @db.Geography(MultiPointZM, 4326) - geogcol25 GeoJson @db.Geography(MultiLineString, 4326) - geogcol26 GeoJson @db.Geography(MultiLineStringZ, 4326) - geogcol27 GeoJson @db.Geography(MultiLineStringM, 4326) - geogcol28 GeoJson @db.Geography(MultiLineStringZM, 4326) - geogcol29 GeoJson @db.Geography(MultiPolygon, 4326) - geogcol30 GeoJson @db.Geography(MultiPolygonZ, 4326) - geogcol31 GeoJson @db.Geography(MultiPolygonM, 4326) - geogcol32 GeoJson @db.Geography(MultiPolygonZM, 4326) - geogcol33 GeoJson @db.Geography(GeometryCollection, 4326) - geogcol34 GeoJson @db.Geography(GeometryCollectionZ, 4326) - geogcol35 GeoJson @db.Geography(GeometryCollectionM, 4326) - geogcol36 GeoJson @db.Geography(GeometryCollectionZM, 4326) + geomcol1 Geometry @db.Geometry(Geometry, 4326) + geomcol2 Geometry @db.Geometry(GeometryZ, 4326) + geomcol3 Geometry @db.Geometry(GeometryM, 4326) + geomcol4 Geometry @db.Geometry(GeometryZM, 4326) + geomcol5 Geometry @db.Geometry(Point, 4326) + geomcol6 Geometry @db.Geometry(PointZ, 4326) + geomcol7 Geometry @db.Geometry(PointM, 4326) + geomcol8 Geometry @db.Geometry(PointZM, 4326) + geomcol9 Geometry @db.Geometry(Point, 4326) + geomcol10 Geometry @db.Geometry(PointZ, 4326) + geomcol11 Geometry @db.Geometry(PointM, 4326) + geomcol12 Geometry @db.Geometry(PointZM, 4326) + geomcol13 Geometry @db.Geometry(LineString, 4326) + geomcol14 Geometry @db.Geometry(LineStringZ, 4326) + geomcol15 Geometry @db.Geometry(LineStringM, 4326) + geomcol16 Geometry @db.Geometry(LineStringZM, 4326) + geomcol17 Geometry @db.Geometry(Polygon, 4326) + geomcol18 Geometry @db.Geometry(PolygonZ, 4326) + geomcol19 Geometry @db.Geometry(PolygonM, 4326) + geomcol20 Geometry @db.Geometry(PolygonZM, 4326) + geomcol21 Geometry @db.Geometry(MultiPoint, 4326) + geomcol22 Geometry @db.Geometry(MultiPointZ, 4326) + geomcol23 Geometry @db.Geometry(MultiPointM, 4326) + geomcol24 Geometry @db.Geometry(MultiPointZM, 4326) + geomcol25 Geometry @db.Geometry(MultiLineString, 4326) + geomcol26 Geometry @db.Geometry(MultiLineStringZ, 4326) + geomcol27 Geometry @db.Geometry(MultiLineStringM, 4326) + geomcol28 Geometry @db.Geometry(MultiLineStringZM, 4326) + geomcol29 Geometry @db.Geometry(MultiPolygon, 4326) + geomcol30 Geometry @db.Geometry(MultiPolygonZ, 4326) + geomcol31 Geometry @db.Geometry(MultiPolygonM, 4326) + geomcol32 Geometry @db.Geometry(MultiPolygonZM, 4326) + geomcol33 Geometry @db.Geometry(GeometryCollection, 4326) + geomcol34 Geometry @db.Geometry(GeometryCollectionZ, 4326) + geomcol35 Geometry @db.Geometry(GeometryCollectionM, 4326) + geomcol36 Geometry @db.Geometry(GeometryCollectionZM, 4326) + geogcol1 Geometry @db.Geography(Geometry, 4326) + geogcol2 Geometry @db.Geography(GeometryZ, 4326) + geogcol3 Geometry @db.Geography(GeometryM, 4326) + geogcol4 Geometry @db.Geography(GeometryZM, 4326) + geogcol5 Geometry @db.Geography(Point, 4326) + geogcol6 Geometry @db.Geography(PointZ, 4326) + geogcol7 Geometry @db.Geography(PointM, 4326) + geogcol8 Geometry @db.Geography(PointZM, 4326) + geogcol9 Geometry @db.Geography(Point, 4326) + geogcol10 Geometry @db.Geography(PointZ, 4326) + geogcol11 Geometry @db.Geography(PointM, 4326) + geogcol12 Geometry @db.Geography(PointZM, 4326) + geogcol13 Geometry @db.Geography(LineString, 4326) + geogcol14 Geometry @db.Geography(LineStringZ, 4326) + geogcol15 Geometry @db.Geography(LineStringM, 4326) + geogcol16 Geometry @db.Geography(LineStringZM, 4326) + geogcol17 Geometry @db.Geography(Polygon, 4326) + geogcol18 Geometry @db.Geography(PolygonZ, 4326) + geogcol19 Geometry @db.Geography(PolygonM, 4326) + geogcol20 Geometry @db.Geography(PolygonZM, 4326) + geogcol21 Geometry @db.Geography(MultiPoint, 4326) + geogcol22 Geometry @db.Geography(MultiPointZ, 4326) + geogcol23 Geometry @db.Geography(MultiPointM, 4326) + geogcol24 Geometry @db.Geography(MultiPointZM, 4326) + geogcol25 Geometry @db.Geography(MultiLineString, 4326) + geogcol26 Geometry @db.Geography(MultiLineStringZ, 4326) + geogcol27 Geometry @db.Geography(MultiLineStringM, 4326) + geogcol28 Geometry @db.Geography(MultiLineStringZM, 4326) + geogcol29 Geometry @db.Geography(MultiPolygon, 4326) + geogcol30 Geometry @db.Geography(MultiPolygonZ, 4326) + geogcol31 Geometry @db.Geography(MultiPolygonM, 4326) + geogcol32 Geometry @db.Geography(MultiPolygonZM, 4326) + geogcol33 Geometry @db.Geography(GeometryCollection, 4326) + geogcol34 Geometry @db.Geography(GeometryCollectionZ, 4326) + geogcol35 Geometry @db.Geography(GeometryCollectionM, 4326) + geogcol36 Geometry @db.Geography(GeometryCollectionZM, 4326) } "#}; diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs index 9ac52a0e8e0d..1ed76824b6fa 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs @@ -475,7 +475,10 @@ mod geometry_create { schema.to_owned() } - #[connector_test(schema(geometry_opt), exclude(Postgres, Sqlite(3, "cfd1", "libsql.js", "libsql.js.wasm")))] + #[connector_test( + schema(geometry_opt), + exclude(Postgres, Sqlite(3, "cfd1", "libsql.js", "libsql.js.wasm")) + )] async fn create_geometry(runner: Runner) -> TestResult<()> { create_geometry_test(runner).await } diff --git a/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs b/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs index 806f5972deb2..b6a3c59ee346 100644 --- a/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs +++ b/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs @@ -57,20 +57,27 @@ impl ScalarFieldExt for ScalarField { (PrismaValue::Bytes(b), _) => Value::bytes(b), (PrismaValue::Object(_), _) => unimplemented!(), (PrismaValue::GeoJson(s), _) => { - let geometry = GeometryValue { - wkt: GeoJson(&s).to_wkt().unwrap(), - srid: 4326, - }; + // GeoJSON string should have been validated before + let wkt = GeoJson(&s).to_wkt().unwrap(); match self.type_family() { - TypeFamily::Geography(_) => Value::geography(geometry), - _ => Value::geometry(geometry), + TypeFamily::Geography(srid) => Value::geography(GeometryValue { + wkt, + srid: srid.unwrap_or(0), + }), + TypeFamily::Geometry(srid) => Value::geometry(GeometryValue { + wkt, + srid: srid.unwrap_or(0), + }), + _ => unreachable!(), } } (PrismaValue::Geometry(s), _) => { + // EWKT string should have been validated before let geometry = GeometryValue::from_str(&s).unwrap(); match self.type_family() { TypeFamily::Geography(_) => Value::geography(geometry), - _ => Value::geometry(geometry), + TypeFamily::Geometry(_) => Value::geometry(geometry), + _ => unreachable!(), } } (PrismaValue::Null, ident) => match ident { diff --git a/query-engine/connectors/sql-query-connector/src/row.rs b/query-engine/connectors/sql-query-connector/src/row.rs index 33320e8d7bd3..b17b4e6740e2 100644 --- a/query-engine/connectors/sql-query-connector/src/row.rs +++ b/query-engine/connectors/sql-query-connector/src/row.rs @@ -303,8 +303,8 @@ fn row_value_to_prisma_value(p_value: Value, meta: ColumnMetadata<'_>) -> Result // the ewkt string back to geojson. However, per specification, GeoJSON geometries // can only be represented with EPSG:4326 projection. Plus WKT can represent more // spatial types than GeoJSON can, so this operation may fail. - ValueType::Text(Some(ref ewkt)) => match ewkt.starts_with("SRID=4326;") { - true => WktStr(&ewkt[10..]) + ValueType::Text(Some(ref ewkt)) => match ewkt.starts_with("SRID=0;") || ewkt.starts_with("SRID=4326;") { + true => WktStr(&ewkt[ewkt.find(";").unwrap() + 1..]) .to_json() .map(PrismaValue::GeoJson) .map_err(|_| create_error(&p_value))?, diff --git a/schema-engine/connectors/sql-schema-connector/src/sql_renderer/sqlite_renderer.rs b/schema-engine/connectors/sql-schema-connector/src/sql_renderer/sqlite_renderer.rs index b27cea04f666..3119b3cc8473 100644 --- a/schema-engine/connectors/sql-schema-connector/src/sql_renderer/sqlite_renderer.rs +++ b/schema-engine/connectors/sql-schema-connector/src/sql_renderer/sqlite_renderer.rs @@ -171,7 +171,7 @@ impl SqlRenderer for SqliteFlavour { "SELECT RecoverGeometryColumn('{table_name}', '{column_name}', {srid}, '{type_}', '{dims}');", srid = geom.srid, type_ = geom.type_.as_2d(), - dims = geom.type_.dimensions(), + dims = geom.type_.dimension(), ) .unwrap(); result From 2a288d0402972dfb1b3ec83000e050fdfaa4a830 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Wed, 2 Oct 2024 17:22:03 +0200 Subject: [PATCH 049/103] Update tests --- .../tests/types/cockroachdb_native_types.rs | 271 ++++++++ psl/psl/tests/types/postgres_native_types.rs | 634 ++++++++++++------ psl/psl/tests/types/sqlite_native_types.rs | 188 +----- 3 files changed, 737 insertions(+), 356 deletions(-) diff --git a/psl/psl/tests/types/cockroachdb_native_types.rs b/psl/psl/tests/types/cockroachdb_native_types.rs index 8466b420107e..0fb445985dc7 100644 --- a/psl/psl/tests/types/cockroachdb_native_types.rs +++ b/psl/psl/tests/types/cockroachdb_native_types.rs @@ -262,6 +262,277 @@ fn cockroach_specific_native_types_are_valid() { psl::parse_schema(schema).unwrap(); } +#[test] +fn should_fail_on_geojson_when_incompatible_geometry_type() { + let dml = indoc! {r#" + datasource db { + provider = "cockroachdb" + url = env("DATABASE_URL") + } + + model Blog { + id Int @id + geomcol1 GeoJson @db.Geometry(GeometryM, 4326) + geomcol2 GeoJson @db.Geometry(GeometryZM, 4326) + geomcol3 GeoJson @db.Geometry(PointM, 4326) + geomcol4 GeoJson @db.Geometry(PointZM, 4326) + geomcol5 GeoJson @db.Geometry(PointM, 4326) + geomcol6 GeoJson @db.Geometry(PointZM, 4326) + geomcol7 GeoJson @db.Geometry(LineStringM, 4326) + geomcol8 GeoJson @db.Geometry(LineStringZM, 4326) + geomcol9 GeoJson @db.Geometry(PolygonM, 4326) + geomcol10 GeoJson @db.Geometry(PolygonZM, 4326) + geomcol11 GeoJson @db.Geometry(MultiPointM, 4326) + geomcol12 GeoJson @db.Geometry(MultiPointZM, 4326) + geomcol13 GeoJson @db.Geometry(MultiLineStringM, 4326) + geomcol14 GeoJson @db.Geometry(MultiLineStringZM, 4326) + geomcol15 GeoJson @db.Geometry(MultiPolygonM, 4326) + geomcol16 GeoJson @db.Geometry(MultiPolygonZM, 4326) + geomcol17 GeoJson @db.Geometry(GeometryCollectionM, 4326) + geomcol18 GeoJson @db.Geometry(GeometryCollectionZM, 4326) + geogcol1 GeoJson @db.Geography(GeometryM, 4326) + geogcol2 GeoJson @db.Geography(GeometryZM, 4326) + geogcol3 GeoJson @db.Geography(PointM, 4326) + geogcol4 GeoJson @db.Geography(PointZM, 4326) + geogcol5 GeoJson @db.Geography(PointM, 4326) + geogcol6 GeoJson @db.Geography(PointZM, 4326) + geogcol7 GeoJson @db.Geography(LineStringM, 4326) + geogcol8 GeoJson @db.Geography(LineStringZM, 4326) + geogcol9 GeoJson @db.Geography(PolygonM, 4326) + geogcol10 GeoJson @db.Geography(PolygonZM, 4326) + geogcol11 GeoJson @db.Geography(MultiPointM, 4326) + geogcol12 GeoJson @db.Geography(MultiPointZM, 4326) + geogcol13 GeoJson @db.Geography(MultiLineStringM, 4326) + geogcol14 GeoJson @db.Geography(MultiLineStringZM, 4326) + geogcol15 GeoJson @db.Geography(MultiPolygonM, 4326) + geogcol16 GeoJson @db.Geography(MultiPolygonZM, 4326) + geogcol17 GeoJson @db.Geography(GeometryCollectionM, 4326) + geogcol18 GeoJson @db.Geography(GeometryCollectionZM, 4326) + } + "#}; + + let expectation = expect![[r#" + error: Argument M is out of range for native type `Geometry(GeometryM,4326)` of CockroachDB: GeometryM isn't compatible with GeoJson. + --> schema.prisma:8 +  |  +  7 |  id Int @id +  8 |  geomcol1 GeoJson @db.Geometry(GeometryM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(GeometryZM,4326)` of CockroachDB: GeometryZM isn't compatible with GeoJson. + --> schema.prisma:9 +  |  +  8 |  geomcol1 GeoJson @db.Geometry(GeometryM, 4326) +  9 |  geomcol2 GeoJson @db.Geometry(GeometryZM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(PointM,4326)` of CockroachDB: PointM isn't compatible with GeoJson. + --> schema.prisma:10 +  |  +  9 |  geomcol2 GeoJson @db.Geometry(GeometryZM, 4326) + 10 |  geomcol3 GeoJson @db.Geometry(PointM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(PointZM,4326)` of CockroachDB: PointZM isn't compatible with GeoJson. + --> schema.prisma:11 +  |  + 10 |  geomcol3 GeoJson @db.Geometry(PointM, 4326) + 11 |  geomcol4 GeoJson @db.Geometry(PointZM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(PointM,4326)` of CockroachDB: PointM isn't compatible with GeoJson. + --> schema.prisma:12 +  |  + 11 |  geomcol4 GeoJson @db.Geometry(PointZM, 4326) + 12 |  geomcol5 GeoJson @db.Geometry(PointM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(PointZM,4326)` of CockroachDB: PointZM isn't compatible with GeoJson. + --> schema.prisma:13 +  |  + 12 |  geomcol5 GeoJson @db.Geometry(PointM, 4326) + 13 |  geomcol6 GeoJson @db.Geometry(PointZM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(LineStringM,4326)` of CockroachDB: LineStringM isn't compatible with GeoJson. + --> schema.prisma:14 +  |  + 13 |  geomcol6 GeoJson @db.Geometry(PointZM, 4326) + 14 |  geomcol7 GeoJson @db.Geometry(LineStringM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(LineStringZM,4326)` of CockroachDB: LineStringZM isn't compatible with GeoJson. + --> schema.prisma:15 +  |  + 14 |  geomcol7 GeoJson @db.Geometry(LineStringM, 4326) + 15 |  geomcol8 GeoJson @db.Geometry(LineStringZM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(PolygonM,4326)` of CockroachDB: PolygonM isn't compatible with GeoJson. + --> schema.prisma:16 +  |  + 15 |  geomcol8 GeoJson @db.Geometry(LineStringZM, 4326) + 16 |  geomcol9 GeoJson @db.Geometry(PolygonM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(PolygonZM,4326)` of CockroachDB: PolygonZM isn't compatible with GeoJson. + --> schema.prisma:17 +  |  + 16 |  geomcol9 GeoJson @db.Geometry(PolygonM, 4326) + 17 |  geomcol10 GeoJson @db.Geometry(PolygonZM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiPointM,4326)` of CockroachDB: MultiPointM isn't compatible with GeoJson. + --> schema.prisma:18 +  |  + 17 |  geomcol10 GeoJson @db.Geometry(PolygonZM, 4326) + 18 |  geomcol11 GeoJson @db.Geometry(MultiPointM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiPointZM,4326)` of CockroachDB: MultiPointZM isn't compatible with GeoJson. + --> schema.prisma:19 +  |  + 18 |  geomcol11 GeoJson @db.Geometry(MultiPointM, 4326) + 19 |  geomcol12 GeoJson @db.Geometry(MultiPointZM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiLineStringM,4326)` of CockroachDB: MultiLineStringM isn't compatible with GeoJson. + --> schema.prisma:20 +  |  + 19 |  geomcol12 GeoJson @db.Geometry(MultiPointZM, 4326) + 20 |  geomcol13 GeoJson @db.Geometry(MultiLineStringM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiLineStringZM,4326)` of CockroachDB: MultiLineStringZM isn't compatible with GeoJson. + --> schema.prisma:21 +  |  + 20 |  geomcol13 GeoJson @db.Geometry(MultiLineStringM, 4326) + 21 |  geomcol14 GeoJson @db.Geometry(MultiLineStringZM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiPolygonM,4326)` of CockroachDB: MultiPolygonM isn't compatible with GeoJson. + --> schema.prisma:22 +  |  + 21 |  geomcol14 GeoJson @db.Geometry(MultiLineStringZM, 4326) + 22 |  geomcol15 GeoJson @db.Geometry(MultiPolygonM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(MultiPolygonZM,4326)` of CockroachDB: MultiPolygonZM isn't compatible with GeoJson. + --> schema.prisma:23 +  |  + 22 |  geomcol15 GeoJson @db.Geometry(MultiPolygonM, 4326) + 23 |  geomcol16 GeoJson @db.Geometry(MultiPolygonZM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(GeometryCollectionM,4326)` of CockroachDB: GeometryCollectionM isn't compatible with GeoJson. + --> schema.prisma:24 +  |  + 23 |  geomcol16 GeoJson @db.Geometry(MultiPolygonZM, 4326) + 24 |  geomcol17 GeoJson @db.Geometry(GeometryCollectionM, 4326) +  |  + error: Argument M is out of range for native type `Geometry(GeometryCollectionZM,4326)` of CockroachDB: GeometryCollectionZM isn't compatible with GeoJson. + --> schema.prisma:25 +  |  + 24 |  geomcol17 GeoJson @db.Geometry(GeometryCollectionM, 4326) + 25 |  geomcol18 GeoJson @db.Geometry(GeometryCollectionZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(GeometryM,4326)` of CockroachDB: GeometryM isn't compatible with GeoJson. + --> schema.prisma:26 +  |  + 25 |  geomcol18 GeoJson @db.Geometry(GeometryCollectionZM, 4326) + 26 |  geogcol1 GeoJson @db.Geography(GeometryM, 4326) +  |  + error: Argument M is out of range for native type `Geography(GeometryZM,4326)` of CockroachDB: GeometryZM isn't compatible with GeoJson. + --> schema.prisma:27 +  |  + 26 |  geogcol1 GeoJson @db.Geography(GeometryM, 4326) + 27 |  geogcol2 GeoJson @db.Geography(GeometryZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(PointM,4326)` of CockroachDB: PointM isn't compatible with GeoJson. + --> schema.prisma:28 +  |  + 27 |  geogcol2 GeoJson @db.Geography(GeometryZM, 4326) + 28 |  geogcol3 GeoJson @db.Geography(PointM, 4326) +  |  + error: Argument M is out of range for native type `Geography(PointZM,4326)` of CockroachDB: PointZM isn't compatible with GeoJson. + --> schema.prisma:29 +  |  + 28 |  geogcol3 GeoJson @db.Geography(PointM, 4326) + 29 |  geogcol4 GeoJson @db.Geography(PointZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(PointM,4326)` of CockroachDB: PointM isn't compatible with GeoJson. + --> schema.prisma:30 +  |  + 29 |  geogcol4 GeoJson @db.Geography(PointZM, 4326) + 30 |  geogcol5 GeoJson @db.Geography(PointM, 4326) +  |  + error: Argument M is out of range for native type `Geography(PointZM,4326)` of CockroachDB: PointZM isn't compatible with GeoJson. + --> schema.prisma:31 +  |  + 30 |  geogcol5 GeoJson @db.Geography(PointM, 4326) + 31 |  geogcol6 GeoJson @db.Geography(PointZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(LineStringM,4326)` of CockroachDB: LineStringM isn't compatible with GeoJson. + --> schema.prisma:32 +  |  + 31 |  geogcol6 GeoJson @db.Geography(PointZM, 4326) + 32 |  geogcol7 GeoJson @db.Geography(LineStringM, 4326) +  |  + error: Argument M is out of range for native type `Geography(LineStringZM,4326)` of CockroachDB: LineStringZM isn't compatible with GeoJson. + --> schema.prisma:33 +  |  + 32 |  geogcol7 GeoJson @db.Geography(LineStringM, 4326) + 33 |  geogcol8 GeoJson @db.Geography(LineStringZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(PolygonM,4326)` of CockroachDB: PolygonM isn't compatible with GeoJson. + --> schema.prisma:34 +  |  + 33 |  geogcol8 GeoJson @db.Geography(LineStringZM, 4326) + 34 |  geogcol9 GeoJson @db.Geography(PolygonM, 4326) +  |  + error: Argument M is out of range for native type `Geography(PolygonZM,4326)` of CockroachDB: PolygonZM isn't compatible with GeoJson. + --> schema.prisma:35 +  |  + 34 |  geogcol9 GeoJson @db.Geography(PolygonM, 4326) + 35 |  geogcol10 GeoJson @db.Geography(PolygonZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiPointM,4326)` of CockroachDB: MultiPointM isn't compatible with GeoJson. + --> schema.prisma:36 +  |  + 35 |  geogcol10 GeoJson @db.Geography(PolygonZM, 4326) + 36 |  geogcol11 GeoJson @db.Geography(MultiPointM, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiPointZM,4326)` of CockroachDB: MultiPointZM isn't compatible with GeoJson. + --> schema.prisma:37 +  |  + 36 |  geogcol11 GeoJson @db.Geography(MultiPointM, 4326) + 37 |  geogcol12 GeoJson @db.Geography(MultiPointZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiLineStringM,4326)` of CockroachDB: MultiLineStringM isn't compatible with GeoJson. + --> schema.prisma:38 +  |  + 37 |  geogcol12 GeoJson @db.Geography(MultiPointZM, 4326) + 38 |  geogcol13 GeoJson @db.Geography(MultiLineStringM, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiLineStringZM,4326)` of CockroachDB: MultiLineStringZM isn't compatible with GeoJson. + --> schema.prisma:39 +  |  + 38 |  geogcol13 GeoJson @db.Geography(MultiLineStringM, 4326) + 39 |  geogcol14 GeoJson @db.Geography(MultiLineStringZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiPolygonM,4326)` of CockroachDB: MultiPolygonM isn't compatible with GeoJson. + --> schema.prisma:40 +  |  + 39 |  geogcol14 GeoJson @db.Geography(MultiLineStringZM, 4326) + 40 |  geogcol15 GeoJson @db.Geography(MultiPolygonM, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiPolygonZM,4326)` of CockroachDB: MultiPolygonZM isn't compatible with GeoJson. + --> schema.prisma:41 +  |  + 40 |  geogcol15 GeoJson @db.Geography(MultiPolygonM, 4326) + 41 |  geogcol16 GeoJson @db.Geography(MultiPolygonZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(GeometryCollectionM,4326)` of CockroachDB: GeometryCollectionM isn't compatible with GeoJson. + --> schema.prisma:42 +  |  + 41 |  geogcol16 GeoJson @db.Geography(MultiPolygonZM, 4326) + 42 |  geogcol17 GeoJson @db.Geography(GeometryCollectionM, 4326) +  |  + error: Argument M is out of range for native type `Geography(GeometryCollectionZM,4326)` of CockroachDB: GeometryCollectionZM isn't compatible with GeoJson. + --> schema.prisma:43 +  |  + 42 |  geogcol17 GeoJson @db.Geography(GeometryCollectionM, 4326) + 43 |  geogcol18 GeoJson @db.Geography(GeometryCollectionZM, 4326) +  |  + "#]]; + + expect_error(dml, &expectation); +} + #[test] fn should_fail_on_geojson_when_invalid_geometry_type() { let dml = indoc! {r#" diff --git a/psl/psl/tests/types/postgres_native_types.rs b/psl/psl/tests/types/postgres_native_types.rs index fca309beb801..29d9ad4732ef 100644 --- a/psl/psl/tests/types/postgres_native_types.rs +++ b/psl/psl/tests/types/postgres_native_types.rs @@ -387,345 +387,597 @@ fn should_fail_on_geojson_when_incompatible_geometry_type() { model Blog { id Int @id - geom_01 GeoJson @db.Geometry(CircularString, 4326) - geom_02 GeoJson @db.Geometry(CircularStringZ, 4326) - geom_03 GeoJson @db.Geometry(CircularStringM, 4326) - geom_04 GeoJson @db.Geometry(CircularStringZM, 4326) - geom_05 GeoJson @db.Geometry(CompoundCurve, 4326) - geom_06 GeoJson @db.Geometry(CompoundCurveZ, 4326) - geom_07 GeoJson @db.Geometry(CompoundCurveM, 4326) - geom_08 GeoJson @db.Geometry(CompoundCurveZM, 4326) - geom_09 GeoJson @db.Geometry(CurvePolygon, 4326) - geom_10 GeoJson @db.Geometry(CurvePolygonZ, 4326) - geom_11 GeoJson @db.Geometry(CurvePolygonM, 4326) - geom_12 GeoJson @db.Geometry(CurvePolygonZM, 4326) - geom_13 GeoJson @db.Geometry(MultiCurve, 4326) - geom_14 GeoJson @db.Geometry(MultiCurveZ, 4326) - geom_15 GeoJson @db.Geometry(MultiCurveM, 4326) - geom_16 GeoJson @db.Geometry(MultiCurveZM, 4326) - geom_17 GeoJson @db.Geometry(MultiSurface, 4326) - geom_18 GeoJson @db.Geometry(MultiSurfaceZ, 4326) - geom_19 GeoJson @db.Geometry(MultiSurfaceM, 4326) - geom_20 GeoJson @db.Geometry(MultiSurfaceZM, 4326) - geom_21 GeoJson @db.Geometry(PolyhedralSurface, 4326) - geom_22 GeoJson @db.Geometry(PolyhedralSurfaceZ, 4326) - geom_23 GeoJson @db.Geometry(PolyhedralSurfaceM, 4326) - geom_24 GeoJson @db.Geometry(PolyhedralSurfaceZM, 4326) - geog_01 GeoJson @db.Geography(CircularString, 4326) - geog_02 GeoJson @db.Geography(CircularStringZ, 4326) - geog_03 GeoJson @db.Geography(CircularStringM, 4326) - geog_04 GeoJson @db.Geography(CircularStringZM, 4326) - geog_05 GeoJson @db.Geography(CompoundCurve, 4326) - geog_06 GeoJson @db.Geography(CompoundCurveZ, 4326) - geog_07 GeoJson @db.Geography(CompoundCurveM, 4326) - geog_08 GeoJson @db.Geography(CompoundCurveZM, 4326) - geog_09 GeoJson @db.Geography(CurvePolygon, 4326) - geog_10 GeoJson @db.Geography(CurvePolygonZ, 4326) - geog_11 GeoJson @db.Geography(CurvePolygonM, 4326) - geog_12 GeoJson @db.Geography(CurvePolygonZM, 4326) - geog_13 GeoJson @db.Geography(MultiCurve, 4326) - geog_14 GeoJson @db.Geography(MultiCurveZ, 4326) - geog_15 GeoJson @db.Geography(MultiCurveM, 4326) - geog_16 GeoJson @db.Geography(MultiCurveZM, 4326) - geog_17 GeoJson @db.Geography(MultiSurface, 4326) - geog_18 GeoJson @db.Geography(MultiSurfaceZ, 4326) - geog_19 GeoJson @db.Geography(MultiSurfaceM, 4326) - geog_20 GeoJson @db.Geography(MultiSurfaceZM, 4326) - geog_21 GeoJson @db.Geography(PolyhedralSurface, 4326) - geog_22 GeoJson @db.Geography(PolyhedralSurfaceZ, 4326) - geog_23 GeoJson @db.Geography(PolyhedralSurfaceM, 4326) - geog_24 GeoJson @db.Geography(PolyhedralSurfaceZM, 4326) + geom_01 GeoJson @db.Geometry(GeometryM, 4326) + geom_02 GeoJson @db.Geometry(GeometryZM, 4326) + geom_03 GeoJson @db.Geometry(PointM, 4326) + geom_04 GeoJson @db.Geometry(PointZM, 4326) + geom_05 GeoJson @db.Geometry(PointM, 4326) + geom_06 GeoJson @db.Geometry(PointZM, 4326) + geom_07 GeoJson @db.Geometry(LineStringM, 4326) + geom_08 GeoJson @db.Geometry(LineStringZM, 4326) + geom_09 GeoJson @db.Geometry(PolygonM, 4326) + geom_10 GeoJson @db.Geometry(PolygonZM, 4326) + geom_11 GeoJson @db.Geometry(MultiPointM, 4326) + geom_12 GeoJson @db.Geometry(MultiPointZM, 4326) + geom_13 GeoJson @db.Geometry(MultiLineStringM, 4326) + geom_14 GeoJson @db.Geometry(MultiLineStringZM, 4326) + geom_15 GeoJson @db.Geometry(MultiPolygonM, 4326) + geom_16 GeoJson @db.Geometry(MultiPolygonZM, 4326) + geom_17 GeoJson @db.Geometry(GeometryCollectionM, 4326) + geom_18 GeoJson @db.Geometry(GeometryCollectionZM, 4326) + geom_19 GeoJson @db.Geometry(CircularString, 4326) + geom_20 GeoJson @db.Geometry(CircularStringZ, 4326) + geom_21 GeoJson @db.Geometry(CircularStringM, 4326) + geom_22 GeoJson @db.Geometry(CircularStringZM, 4326) + geom_23 GeoJson @db.Geometry(CompoundCurve, 4326) + geom_24 GeoJson @db.Geometry(CompoundCurveZ, 4326) + geom_35 GeoJson @db.Geometry(CompoundCurveM, 4326) + geom_36 GeoJson @db.Geometry(CompoundCurveZM, 4326) + geom_37 GeoJson @db.Geometry(CurvePolygon, 4326) + geom_38 GeoJson @db.Geometry(CurvePolygonZ, 4326) + geom_39 GeoJson @db.Geometry(CurvePolygonM, 4326) + geom_40 GeoJson @db.Geometry(CurvePolygonZM, 4326) + geom_41 GeoJson @db.Geometry(MultiCurve, 4326) + geom_42 GeoJson @db.Geometry(MultiCurveZ, 4326) + geom_43 GeoJson @db.Geometry(MultiCurveM, 4326) + geom_44 GeoJson @db.Geometry(MultiCurveZM, 4326) + geom_45 GeoJson @db.Geometry(MultiSurface, 4326) + geom_46 GeoJson @db.Geometry(MultiSurfaceZ, 4326) + geom_47 GeoJson @db.Geometry(MultiSurfaceM, 4326) + geom_48 GeoJson @db.Geometry(MultiSurfaceZM, 4326) + geom_49 GeoJson @db.Geometry(PolyhedralSurface, 4326) + geom_50 GeoJson @db.Geometry(PolyhedralSurfaceZ, 4326) + geom_51 GeoJson @db.Geometry(PolyhedralSurfaceM, 4326) + geom_52 GeoJson @db.Geometry(PolyhedralSurfaceZM, 4326) + geog_01 GeoJson @db.Geography(GeometryM, 4326) + geog_02 GeoJson @db.Geography(GeometryZM, 4326) + geog_03 GeoJson @db.Geography(PointM, 4326) + geog_04 GeoJson @db.Geography(PointZM, 4326) + geog_05 GeoJson @db.Geography(PointM, 4326) + geog_06 GeoJson @db.Geography(PointZM, 4326) + geog_07 GeoJson @db.Geography(LineStringM, 4326) + geog_08 GeoJson @db.Geography(LineStringZM, 4326) + geog_09 GeoJson @db.Geography(PolygonM, 4326) + geog_10 GeoJson @db.Geography(PolygonZM, 4326) + geog_11 GeoJson @db.Geography(MultiPointM, 4326) + geog_12 GeoJson @db.Geography(MultiPointZM, 4326) + geog_13 GeoJson @db.Geography(MultiLineStringM, 4326) + geog_14 GeoJson @db.Geography(MultiLineStringZM, 4326) + geog_15 GeoJson @db.Geography(MultiPolygonM, 4326) + geog_16 GeoJson @db.Geography(MultiPolygonZM, 4326) + geog_17 GeoJson @db.Geography(GeometryCollectionM, 4326) + geog_18 GeoJson @db.Geography(GeometryCollectionZM, 4326) + geog_19 GeoJson @db.Geography(CircularString, 4326) + geog_20 GeoJson @db.Geography(CircularStringZ, 4326) + geog_21 GeoJson @db.Geography(CircularStringM, 4326) + geog_22 GeoJson @db.Geography(CircularStringZM, 4326) + geog_23 GeoJson @db.Geography(CompoundCurve, 4326) + geog_24 GeoJson @db.Geography(CompoundCurveZ, 4326) + geog_35 GeoJson @db.Geography(CompoundCurveM, 4326) + geog_36 GeoJson @db.Geography(CompoundCurveZM, 4326) + geog_37 GeoJson @db.Geography(CurvePolygon, 4326) + geog_38 GeoJson @db.Geography(CurvePolygonZ, 4326) + geog_39 GeoJson @db.Geography(CurvePolygonM, 4326) + geog_40 GeoJson @db.Geography(CurvePolygonZM, 4326) + geog_41 GeoJson @db.Geography(MultiCurve, 4326) + geog_42 GeoJson @db.Geography(MultiCurveZ, 4326) + geog_43 GeoJson @db.Geography(MultiCurveM, 4326) + geog_44 GeoJson @db.Geography(MultiCurveZM, 4326) + geog_45 GeoJson @db.Geography(MultiSurface, 4326) + geog_46 GeoJson @db.Geography(MultiSurfaceZ, 4326) + geog_47 GeoJson @db.Geography(MultiSurfaceM, 4326) + geog_48 GeoJson @db.Geography(MultiSurfaceZM, 4326) + geog_49 GeoJson @db.Geography(PolyhedralSurface, 4326) + geog_50 GeoJson @db.Geography(PolyhedralSurfaceZ, 4326) + geog_51 GeoJson @db.Geography(PolyhedralSurfaceM, 4326) + geog_52 GeoJson @db.Geography(PolyhedralSurfaceZM, 4326) } "#}; let expectation = expect![[r#" - error: Argument M is out of range for native type `Geometry(CircularString,4326)` of Postgres: CircularString isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(GeometryM,4326)` of Postgres: GeometryM isn't compatible with GeoJson. --> schema.prisma:8  |   7 |  id Int @id -  8 |  geom_01 GeoJson @db.Geometry(CircularString, 4326) +  8 |  geom_01 GeoJson @db.Geometry(GeometryM, 4326)  |  - error: Argument M is out of range for native type `Geometry(CircularStringZ,4326)` of Postgres: CircularStringZ isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(GeometryZM,4326)` of Postgres: GeometryZM isn't compatible with GeoJson. --> schema.prisma:9  |  -  8 |  geom_01 GeoJson @db.Geometry(CircularString, 4326) -  9 |  geom_02 GeoJson @db.Geometry(CircularStringZ, 4326) +  8 |  geom_01 GeoJson @db.Geometry(GeometryM, 4326) +  9 |  geom_02 GeoJson @db.Geometry(GeometryZM, 4326)  |  - error: Argument M is out of range for native type `Geometry(CircularStringM,4326)` of Postgres: CircularStringM isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(PointM,4326)` of Postgres: PointM isn't compatible with GeoJson. --> schema.prisma:10  |  -  9 |  geom_02 GeoJson @db.Geometry(CircularStringZ, 4326) - 10 |  geom_03 GeoJson @db.Geometry(CircularStringM, 4326) +  9 |  geom_02 GeoJson @db.Geometry(GeometryZM, 4326) + 10 |  geom_03 GeoJson @db.Geometry(PointM, 4326)  |  - error: Argument M is out of range for native type `Geometry(CircularStringZM,4326)` of Postgres: CircularStringZM isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(PointZM,4326)` of Postgres: PointZM isn't compatible with GeoJson. --> schema.prisma:11  |  - 10 |  geom_03 GeoJson @db.Geometry(CircularStringM, 4326) - 11 |  geom_04 GeoJson @db.Geometry(CircularStringZM, 4326) + 10 |  geom_03 GeoJson @db.Geometry(PointM, 4326) + 11 |  geom_04 GeoJson @db.Geometry(PointZM, 4326)  |  - error: Argument M is out of range for native type `Geometry(CompoundCurve,4326)` of Postgres: CompoundCurve isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(PointM,4326)` of Postgres: PointM isn't compatible with GeoJson. --> schema.prisma:12  |  - 11 |  geom_04 GeoJson @db.Geometry(CircularStringZM, 4326) - 12 |  geom_05 GeoJson @db.Geometry(CompoundCurve, 4326) + 11 |  geom_04 GeoJson @db.Geometry(PointZM, 4326) + 12 |  geom_05 GeoJson @db.Geometry(PointM, 4326)  |  - error: Argument M is out of range for native type `Geometry(CompoundCurveZ,4326)` of Postgres: CompoundCurveZ isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(PointZM,4326)` of Postgres: PointZM isn't compatible with GeoJson. --> schema.prisma:13  |  - 12 |  geom_05 GeoJson @db.Geometry(CompoundCurve, 4326) - 13 |  geom_06 GeoJson @db.Geometry(CompoundCurveZ, 4326) + 12 |  geom_05 GeoJson @db.Geometry(PointM, 4326) + 13 |  geom_06 GeoJson @db.Geometry(PointZM, 4326)  |  - error: Argument M is out of range for native type `Geometry(CompoundCurveM,4326)` of Postgres: CompoundCurveM isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(LineStringM,4326)` of Postgres: LineStringM isn't compatible with GeoJson. --> schema.prisma:14  |  - 13 |  geom_06 GeoJson @db.Geometry(CompoundCurveZ, 4326) - 14 |  geom_07 GeoJson @db.Geometry(CompoundCurveM, 4326) + 13 |  geom_06 GeoJson @db.Geometry(PointZM, 4326) + 14 |  geom_07 GeoJson @db.Geometry(LineStringM, 4326)  |  - error: Argument M is out of range for native type `Geometry(CompoundCurveZM,4326)` of Postgres: CompoundCurveZM isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(LineStringZM,4326)` of Postgres: LineStringZM isn't compatible with GeoJson. --> schema.prisma:15  |  - 14 |  geom_07 GeoJson @db.Geometry(CompoundCurveM, 4326) - 15 |  geom_08 GeoJson @db.Geometry(CompoundCurveZM, 4326) + 14 |  geom_07 GeoJson @db.Geometry(LineStringM, 4326) + 15 |  geom_08 GeoJson @db.Geometry(LineStringZM, 4326)  |  - error: Argument M is out of range for native type `Geometry(CurvePolygon,4326)` of Postgres: CurvePolygon isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(PolygonM,4326)` of Postgres: PolygonM isn't compatible with GeoJson. --> schema.prisma:16  |  - 15 |  geom_08 GeoJson @db.Geometry(CompoundCurveZM, 4326) - 16 |  geom_09 GeoJson @db.Geometry(CurvePolygon, 4326) + 15 |  geom_08 GeoJson @db.Geometry(LineStringZM, 4326) + 16 |  geom_09 GeoJson @db.Geometry(PolygonM, 4326)  |  - error: Argument M is out of range for native type `Geometry(CurvePolygonZ,4326)` of Postgres: CurvePolygonZ isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(PolygonZM,4326)` of Postgres: PolygonZM isn't compatible with GeoJson. --> schema.prisma:17  |  - 16 |  geom_09 GeoJson @db.Geometry(CurvePolygon, 4326) - 17 |  geom_10 GeoJson @db.Geometry(CurvePolygonZ, 4326) + 16 |  geom_09 GeoJson @db.Geometry(PolygonM, 4326) + 17 |  geom_10 GeoJson @db.Geometry(PolygonZM, 4326)  |  - error: Argument M is out of range for native type `Geometry(CurvePolygonM,4326)` of Postgres: CurvePolygonM isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(MultiPointM,4326)` of Postgres: MultiPointM isn't compatible with GeoJson. --> schema.prisma:18  |  - 17 |  geom_10 GeoJson @db.Geometry(CurvePolygonZ, 4326) - 18 |  geom_11 GeoJson @db.Geometry(CurvePolygonM, 4326) + 17 |  geom_10 GeoJson @db.Geometry(PolygonZM, 4326) + 18 |  geom_11 GeoJson @db.Geometry(MultiPointM, 4326)  |  - error: Argument M is out of range for native type `Geometry(CurvePolygonZM,4326)` of Postgres: CurvePolygonZM isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(MultiPointZM,4326)` of Postgres: MultiPointZM isn't compatible with GeoJson. --> schema.prisma:19  |  - 18 |  geom_11 GeoJson @db.Geometry(CurvePolygonM, 4326) - 19 |  geom_12 GeoJson @db.Geometry(CurvePolygonZM, 4326) + 18 |  geom_11 GeoJson @db.Geometry(MultiPointM, 4326) + 19 |  geom_12 GeoJson @db.Geometry(MultiPointZM, 4326)  |  - error: Argument M is out of range for native type `Geometry(MultiCurve,4326)` of Postgres: MultiCurve isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(MultiLineStringM,4326)` of Postgres: MultiLineStringM isn't compatible with GeoJson. --> schema.prisma:20  |  - 19 |  geom_12 GeoJson @db.Geometry(CurvePolygonZM, 4326) - 20 |  geom_13 GeoJson @db.Geometry(MultiCurve, 4326) + 19 |  geom_12 GeoJson @db.Geometry(MultiPointZM, 4326) + 20 |  geom_13 GeoJson @db.Geometry(MultiLineStringM, 4326)  |  - error: Argument M is out of range for native type `Geometry(MultiCurveZ,4326)` of Postgres: MultiCurveZ isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(MultiLineStringZM,4326)` of Postgres: MultiLineStringZM isn't compatible with GeoJson. --> schema.prisma:21  |  - 20 |  geom_13 GeoJson @db.Geometry(MultiCurve, 4326) - 21 |  geom_14 GeoJson @db.Geometry(MultiCurveZ, 4326) + 20 |  geom_13 GeoJson @db.Geometry(MultiLineStringM, 4326) + 21 |  geom_14 GeoJson @db.Geometry(MultiLineStringZM, 4326)  |  - error: Argument M is out of range for native type `Geometry(MultiCurveM,4326)` of Postgres: MultiCurveM isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(MultiPolygonM,4326)` of Postgres: MultiPolygonM isn't compatible with GeoJson. --> schema.prisma:22  |  - 21 |  geom_14 GeoJson @db.Geometry(MultiCurveZ, 4326) - 22 |  geom_15 GeoJson @db.Geometry(MultiCurveM, 4326) + 21 |  geom_14 GeoJson @db.Geometry(MultiLineStringZM, 4326) + 22 |  geom_15 GeoJson @db.Geometry(MultiPolygonM, 4326)  |  - error: Argument M is out of range for native type `Geometry(MultiCurveZM,4326)` of Postgres: MultiCurveZM isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(MultiPolygonZM,4326)` of Postgres: MultiPolygonZM isn't compatible with GeoJson. --> schema.prisma:23  |  - 22 |  geom_15 GeoJson @db.Geometry(MultiCurveM, 4326) - 23 |  geom_16 GeoJson @db.Geometry(MultiCurveZM, 4326) + 22 |  geom_15 GeoJson @db.Geometry(MultiPolygonM, 4326) + 23 |  geom_16 GeoJson @db.Geometry(MultiPolygonZM, 4326)  |  - error: Argument M is out of range for native type `Geometry(MultiSurface,4326)` of Postgres: MultiSurface isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(GeometryCollectionM,4326)` of Postgres: GeometryCollectionM isn't compatible with GeoJson. --> schema.prisma:24  |  - 23 |  geom_16 GeoJson @db.Geometry(MultiCurveZM, 4326) - 24 |  geom_17 GeoJson @db.Geometry(MultiSurface, 4326) + 23 |  geom_16 GeoJson @db.Geometry(MultiPolygonZM, 4326) + 24 |  geom_17 GeoJson @db.Geometry(GeometryCollectionM, 4326)  |  - error: Argument M is out of range for native type `Geometry(MultiSurfaceZ,4326)` of Postgres: MultiSurfaceZ isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(GeometryCollectionZM,4326)` of Postgres: GeometryCollectionZM isn't compatible with GeoJson. --> schema.prisma:25  |  - 24 |  geom_17 GeoJson @db.Geometry(MultiSurface, 4326) - 25 |  geom_18 GeoJson @db.Geometry(MultiSurfaceZ, 4326) + 24 |  geom_17 GeoJson @db.Geometry(GeometryCollectionM, 4326) + 25 |  geom_18 GeoJson @db.Geometry(GeometryCollectionZM, 4326)  |  - error: Argument M is out of range for native type `Geometry(MultiSurfaceM,4326)` of Postgres: MultiSurfaceM isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(CircularString,4326)` of Postgres: CircularString isn't compatible with GeoJson. --> schema.prisma:26  |  - 25 |  geom_18 GeoJson @db.Geometry(MultiSurfaceZ, 4326) - 26 |  geom_19 GeoJson @db.Geometry(MultiSurfaceM, 4326) + 25 |  geom_18 GeoJson @db.Geometry(GeometryCollectionZM, 4326) + 26 |  geom_19 GeoJson @db.Geometry(CircularString, 4326)  |  - error: Argument M is out of range for native type `Geometry(MultiSurfaceZM,4326)` of Postgres: MultiSurfaceZM isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(CircularStringZ,4326)` of Postgres: CircularStringZ isn't compatible with GeoJson. --> schema.prisma:27  |  - 26 |  geom_19 GeoJson @db.Geometry(MultiSurfaceM, 4326) - 27 |  geom_20 GeoJson @db.Geometry(MultiSurfaceZM, 4326) + 26 |  geom_19 GeoJson @db.Geometry(CircularString, 4326) + 27 |  geom_20 GeoJson @db.Geometry(CircularStringZ, 4326)  |  - error: Argument M is out of range for native type `Geometry(PolyhedralSurface,4326)` of Postgres: PolyhedralSurface isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(CircularStringM,4326)` of Postgres: CircularStringM isn't compatible with GeoJson. --> schema.prisma:28  |  - 27 |  geom_20 GeoJson @db.Geometry(MultiSurfaceZM, 4326) - 28 |  geom_21 GeoJson @db.Geometry(PolyhedralSurface, 4326) + 27 |  geom_20 GeoJson @db.Geometry(CircularStringZ, 4326) + 28 |  geom_21 GeoJson @db.Geometry(CircularStringM, 4326)  |  - error: Argument M is out of range for native type `Geometry(PolyhedralSurfaceZ,4326)` of Postgres: PolyhedralSurfaceZ isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(CircularStringZM,4326)` of Postgres: CircularStringZM isn't compatible with GeoJson. --> schema.prisma:29  |  - 28 |  geom_21 GeoJson @db.Geometry(PolyhedralSurface, 4326) - 29 |  geom_22 GeoJson @db.Geometry(PolyhedralSurfaceZ, 4326) + 28 |  geom_21 GeoJson @db.Geometry(CircularStringM, 4326) + 29 |  geom_22 GeoJson @db.Geometry(CircularStringZM, 4326)  |  - error: Argument M is out of range for native type `Geometry(PolyhedralSurfaceM,4326)` of Postgres: PolyhedralSurfaceM isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(CompoundCurve,4326)` of Postgres: CompoundCurve isn't compatible with GeoJson. --> schema.prisma:30  |  - 29 |  geom_22 GeoJson @db.Geometry(PolyhedralSurfaceZ, 4326) - 30 |  geom_23 GeoJson @db.Geometry(PolyhedralSurfaceM, 4326) + 29 |  geom_22 GeoJson @db.Geometry(CircularStringZM, 4326) + 30 |  geom_23 GeoJson @db.Geometry(CompoundCurve, 4326)  |  - error: Argument M is out of range for native type `Geometry(PolyhedralSurfaceZM,4326)` of Postgres: PolyhedralSurfaceZM isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(CompoundCurveZ,4326)` of Postgres: CompoundCurveZ isn't compatible with GeoJson. --> schema.prisma:31  |  - 30 |  geom_23 GeoJson @db.Geometry(PolyhedralSurfaceM, 4326) - 31 |  geom_24 GeoJson @db.Geometry(PolyhedralSurfaceZM, 4326) + 30 |  geom_23 GeoJson @db.Geometry(CompoundCurve, 4326) + 31 |  geom_24 GeoJson @db.Geometry(CompoundCurveZ, 4326)  |  - error: Argument M is out of range for native type `Geography(CircularString,4326)` of Postgres: CircularString isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(CompoundCurveM,4326)` of Postgres: CompoundCurveM isn't compatible with GeoJson. --> schema.prisma:32  |  - 31 |  geom_24 GeoJson @db.Geometry(PolyhedralSurfaceZM, 4326) - 32 |  geog_01 GeoJson @db.Geography(CircularString, 4326) + 31 |  geom_24 GeoJson @db.Geometry(CompoundCurveZ, 4326) + 32 |  geom_35 GeoJson @db.Geometry(CompoundCurveM, 4326)  |  - error: Argument M is out of range for native type `Geography(CircularStringZ,4326)` of Postgres: CircularStringZ isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(CompoundCurveZM,4326)` of Postgres: CompoundCurveZM isn't compatible with GeoJson. --> schema.prisma:33  |  - 32 |  geog_01 GeoJson @db.Geography(CircularString, 4326) - 33 |  geog_02 GeoJson @db.Geography(CircularStringZ, 4326) + 32 |  geom_35 GeoJson @db.Geometry(CompoundCurveM, 4326) + 33 |  geom_36 GeoJson @db.Geometry(CompoundCurveZM, 4326)  |  - error: Argument M is out of range for native type `Geography(CircularStringM,4326)` of Postgres: CircularStringM isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(CurvePolygon,4326)` of Postgres: CurvePolygon isn't compatible with GeoJson. --> schema.prisma:34  |  - 33 |  geog_02 GeoJson @db.Geography(CircularStringZ, 4326) - 34 |  geog_03 GeoJson @db.Geography(CircularStringM, 4326) + 33 |  geom_36 GeoJson @db.Geometry(CompoundCurveZM, 4326) + 34 |  geom_37 GeoJson @db.Geometry(CurvePolygon, 4326)  |  - error: Argument M is out of range for native type `Geography(CircularStringZM,4326)` of Postgres: CircularStringZM isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(CurvePolygonZ,4326)` of Postgres: CurvePolygonZ isn't compatible with GeoJson. --> schema.prisma:35  |  - 34 |  geog_03 GeoJson @db.Geography(CircularStringM, 4326) - 35 |  geog_04 GeoJson @db.Geography(CircularStringZM, 4326) + 34 |  geom_37 GeoJson @db.Geometry(CurvePolygon, 4326) + 35 |  geom_38 GeoJson @db.Geometry(CurvePolygonZ, 4326)  |  - error: Argument M is out of range for native type `Geography(CompoundCurve,4326)` of Postgres: CompoundCurve isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(CurvePolygonM,4326)` of Postgres: CurvePolygonM isn't compatible with GeoJson. --> schema.prisma:36  |  - 35 |  geog_04 GeoJson @db.Geography(CircularStringZM, 4326) - 36 |  geog_05 GeoJson @db.Geography(CompoundCurve, 4326) + 35 |  geom_38 GeoJson @db.Geometry(CurvePolygonZ, 4326) + 36 |  geom_39 GeoJson @db.Geometry(CurvePolygonM, 4326)  |  - error: Argument M is out of range for native type `Geography(CompoundCurveZ,4326)` of Postgres: CompoundCurveZ isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(CurvePolygonZM,4326)` of Postgres: CurvePolygonZM isn't compatible with GeoJson. --> schema.prisma:37  |  - 36 |  geog_05 GeoJson @db.Geography(CompoundCurve, 4326) - 37 |  geog_06 GeoJson @db.Geography(CompoundCurveZ, 4326) + 36 |  geom_39 GeoJson @db.Geometry(CurvePolygonM, 4326) + 37 |  geom_40 GeoJson @db.Geometry(CurvePolygonZM, 4326)  |  - error: Argument M is out of range for native type `Geography(CompoundCurveM,4326)` of Postgres: CompoundCurveM isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(MultiCurve,4326)` of Postgres: MultiCurve isn't compatible with GeoJson. --> schema.prisma:38  |  - 37 |  geog_06 GeoJson @db.Geography(CompoundCurveZ, 4326) - 38 |  geog_07 GeoJson @db.Geography(CompoundCurveM, 4326) + 37 |  geom_40 GeoJson @db.Geometry(CurvePolygonZM, 4326) + 38 |  geom_41 GeoJson @db.Geometry(MultiCurve, 4326)  |  - error: Argument M is out of range for native type `Geography(CompoundCurveZM,4326)` of Postgres: CompoundCurveZM isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(MultiCurveZ,4326)` of Postgres: MultiCurveZ isn't compatible with GeoJson. --> schema.prisma:39  |  - 38 |  geog_07 GeoJson @db.Geography(CompoundCurveM, 4326) - 39 |  geog_08 GeoJson @db.Geography(CompoundCurveZM, 4326) + 38 |  geom_41 GeoJson @db.Geometry(MultiCurve, 4326) + 39 |  geom_42 GeoJson @db.Geometry(MultiCurveZ, 4326)  |  - error: Argument M is out of range for native type `Geography(CurvePolygon,4326)` of Postgres: CurvePolygon isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(MultiCurveM,4326)` of Postgres: MultiCurveM isn't compatible with GeoJson. --> schema.prisma:40  |  - 39 |  geog_08 GeoJson @db.Geography(CompoundCurveZM, 4326) - 40 |  geog_09 GeoJson @db.Geography(CurvePolygon, 4326) + 39 |  geom_42 GeoJson @db.Geometry(MultiCurveZ, 4326) + 40 |  geom_43 GeoJson @db.Geometry(MultiCurveM, 4326)  |  - error: Argument M is out of range for native type `Geography(CurvePolygonZ,4326)` of Postgres: CurvePolygonZ isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(MultiCurveZM,4326)` of Postgres: MultiCurveZM isn't compatible with GeoJson. --> schema.prisma:41  |  - 40 |  geog_09 GeoJson @db.Geography(CurvePolygon, 4326) - 41 |  geog_10 GeoJson @db.Geography(CurvePolygonZ, 4326) + 40 |  geom_43 GeoJson @db.Geometry(MultiCurveM, 4326) + 41 |  geom_44 GeoJson @db.Geometry(MultiCurveZM, 4326)  |  - error: Argument M is out of range for native type `Geography(CurvePolygonM,4326)` of Postgres: CurvePolygonM isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(MultiSurface,4326)` of Postgres: MultiSurface isn't compatible with GeoJson. --> schema.prisma:42  |  - 41 |  geog_10 GeoJson @db.Geography(CurvePolygonZ, 4326) - 42 |  geog_11 GeoJson @db.Geography(CurvePolygonM, 4326) + 41 |  geom_44 GeoJson @db.Geometry(MultiCurveZM, 4326) + 42 |  geom_45 GeoJson @db.Geometry(MultiSurface, 4326)  |  - error: Argument M is out of range for native type `Geography(CurvePolygonZM,4326)` of Postgres: CurvePolygonZM isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(MultiSurfaceZ,4326)` of Postgres: MultiSurfaceZ isn't compatible with GeoJson. --> schema.prisma:43  |  - 42 |  geog_11 GeoJson @db.Geography(CurvePolygonM, 4326) - 43 |  geog_12 GeoJson @db.Geography(CurvePolygonZM, 4326) + 42 |  geom_45 GeoJson @db.Geometry(MultiSurface, 4326) + 43 |  geom_46 GeoJson @db.Geometry(MultiSurfaceZ, 4326)  |  - error: Argument M is out of range for native type `Geography(MultiCurve,4326)` of Postgres: MultiCurve isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(MultiSurfaceM,4326)` of Postgres: MultiSurfaceM isn't compatible with GeoJson. --> schema.prisma:44  |  - 43 |  geog_12 GeoJson @db.Geography(CurvePolygonZM, 4326) - 44 |  geog_13 GeoJson @db.Geography(MultiCurve, 4326) + 43 |  geom_46 GeoJson @db.Geometry(MultiSurfaceZ, 4326) + 44 |  geom_47 GeoJson @db.Geometry(MultiSurfaceM, 4326)  |  - error: Argument M is out of range for native type `Geography(MultiCurveZ,4326)` of Postgres: MultiCurveZ isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(MultiSurfaceZM,4326)` of Postgres: MultiSurfaceZM isn't compatible with GeoJson. --> schema.prisma:45  |  - 44 |  geog_13 GeoJson @db.Geography(MultiCurve, 4326) - 45 |  geog_14 GeoJson @db.Geography(MultiCurveZ, 4326) + 44 |  geom_47 GeoJson @db.Geometry(MultiSurfaceM, 4326) + 45 |  geom_48 GeoJson @db.Geometry(MultiSurfaceZM, 4326)  |  - error: Argument M is out of range for native type `Geography(MultiCurveM,4326)` of Postgres: MultiCurveM isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(PolyhedralSurface,4326)` of Postgres: PolyhedralSurface isn't compatible with GeoJson. --> schema.prisma:46  |  - 45 |  geog_14 GeoJson @db.Geography(MultiCurveZ, 4326) - 46 |  geog_15 GeoJson @db.Geography(MultiCurveM, 4326) + 45 |  geom_48 GeoJson @db.Geometry(MultiSurfaceZM, 4326) + 46 |  geom_49 GeoJson @db.Geometry(PolyhedralSurface, 4326)  |  - error: Argument M is out of range for native type `Geography(MultiCurveZM,4326)` of Postgres: MultiCurveZM isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(PolyhedralSurfaceZ,4326)` of Postgres: PolyhedralSurfaceZ isn't compatible with GeoJson. --> schema.prisma:47  |  - 46 |  geog_15 GeoJson @db.Geography(MultiCurveM, 4326) - 47 |  geog_16 GeoJson @db.Geography(MultiCurveZM, 4326) + 46 |  geom_49 GeoJson @db.Geometry(PolyhedralSurface, 4326) + 47 |  geom_50 GeoJson @db.Geometry(PolyhedralSurfaceZ, 4326)  |  - error: Argument M is out of range for native type `Geography(MultiSurface,4326)` of Postgres: MultiSurface isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(PolyhedralSurfaceM,4326)` of Postgres: PolyhedralSurfaceM isn't compatible with GeoJson. --> schema.prisma:48  |  - 47 |  geog_16 GeoJson @db.Geography(MultiCurveZM, 4326) - 48 |  geog_17 GeoJson @db.Geography(MultiSurface, 4326) + 47 |  geom_50 GeoJson @db.Geometry(PolyhedralSurfaceZ, 4326) + 48 |  geom_51 GeoJson @db.Geometry(PolyhedralSurfaceM, 4326)  |  - error: Argument M is out of range for native type `Geography(MultiSurfaceZ,4326)` of Postgres: MultiSurfaceZ isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geometry(PolyhedralSurfaceZM,4326)` of Postgres: PolyhedralSurfaceZM isn't compatible with GeoJson. --> schema.prisma:49  |  - 48 |  geog_17 GeoJson @db.Geography(MultiSurface, 4326) - 49 |  geog_18 GeoJson @db.Geography(MultiSurfaceZ, 4326) + 48 |  geom_51 GeoJson @db.Geometry(PolyhedralSurfaceM, 4326) + 49 |  geom_52 GeoJson @db.Geometry(PolyhedralSurfaceZM, 4326)  |  - error: Argument M is out of range for native type `Geography(MultiSurfaceM,4326)` of Postgres: MultiSurfaceM isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geography(GeometryM,4326)` of Postgres: GeometryM isn't compatible with GeoJson. --> schema.prisma:50  |  - 49 |  geog_18 GeoJson @db.Geography(MultiSurfaceZ, 4326) - 50 |  geog_19 GeoJson @db.Geography(MultiSurfaceM, 4326) + 49 |  geom_52 GeoJson @db.Geometry(PolyhedralSurfaceZM, 4326) + 50 |  geog_01 GeoJson @db.Geography(GeometryM, 4326)  |  - error: Argument M is out of range for native type `Geography(MultiSurfaceZM,4326)` of Postgres: MultiSurfaceZM isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geography(GeometryZM,4326)` of Postgres: GeometryZM isn't compatible with GeoJson. --> schema.prisma:51  |  - 50 |  geog_19 GeoJson @db.Geography(MultiSurfaceM, 4326) - 51 |  geog_20 GeoJson @db.Geography(MultiSurfaceZM, 4326) + 50 |  geog_01 GeoJson @db.Geography(GeometryM, 4326) + 51 |  geog_02 GeoJson @db.Geography(GeometryZM, 4326)  |  - error: Argument M is out of range for native type `Geography(PolyhedralSurface,4326)` of Postgres: PolyhedralSurface isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geography(PointM,4326)` of Postgres: PointM isn't compatible with GeoJson. --> schema.prisma:52  |  - 51 |  geog_20 GeoJson @db.Geography(MultiSurfaceZM, 4326) - 52 |  geog_21 GeoJson @db.Geography(PolyhedralSurface, 4326) + 51 |  geog_02 GeoJson @db.Geography(GeometryZM, 4326) + 52 |  geog_03 GeoJson @db.Geography(PointM, 4326)  |  - error: Argument M is out of range for native type `Geography(PolyhedralSurfaceZ,4326)` of Postgres: PolyhedralSurfaceZ isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geography(PointZM,4326)` of Postgres: PointZM isn't compatible with GeoJson. --> schema.prisma:53  |  - 52 |  geog_21 GeoJson @db.Geography(PolyhedralSurface, 4326) - 53 |  geog_22 GeoJson @db.Geography(PolyhedralSurfaceZ, 4326) + 52 |  geog_03 GeoJson @db.Geography(PointM, 4326) + 53 |  geog_04 GeoJson @db.Geography(PointZM, 4326)  |  - error: Argument M is out of range for native type `Geography(PolyhedralSurfaceM,4326)` of Postgres: PolyhedralSurfaceM isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geography(PointM,4326)` of Postgres: PointM isn't compatible with GeoJson. --> schema.prisma:54  |  - 53 |  geog_22 GeoJson @db.Geography(PolyhedralSurfaceZ, 4326) - 54 |  geog_23 GeoJson @db.Geography(PolyhedralSurfaceM, 4326) + 53 |  geog_04 GeoJson @db.Geography(PointZM, 4326) + 54 |  geog_05 GeoJson @db.Geography(PointM, 4326)  |  - error: Argument M is out of range for native type `Geography(PolyhedralSurfaceZM,4326)` of Postgres: PolyhedralSurfaceZM isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geography(PointZM,4326)` of Postgres: PointZM isn't compatible with GeoJson. --> schema.prisma:55  |  - 54 |  geog_23 GeoJson @db.Geography(PolyhedralSurfaceM, 4326) - 55 |  geog_24 GeoJson @db.Geography(PolyhedralSurfaceZM, 4326) + 54 |  geog_05 GeoJson @db.Geography(PointM, 4326) + 55 |  geog_06 GeoJson @db.Geography(PointZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(LineStringM,4326)` of Postgres: LineStringM isn't compatible with GeoJson. + --> schema.prisma:56 +  |  + 55 |  geog_06 GeoJson @db.Geography(PointZM, 4326) + 56 |  geog_07 GeoJson @db.Geography(LineStringM, 4326) +  |  + error: Argument M is out of range for native type `Geography(LineStringZM,4326)` of Postgres: LineStringZM isn't compatible with GeoJson. + --> schema.prisma:57 +  |  + 56 |  geog_07 GeoJson @db.Geography(LineStringM, 4326) + 57 |  geog_08 GeoJson @db.Geography(LineStringZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(PolygonM,4326)` of Postgres: PolygonM isn't compatible with GeoJson. + --> schema.prisma:58 +  |  + 57 |  geog_08 GeoJson @db.Geography(LineStringZM, 4326) + 58 |  geog_09 GeoJson @db.Geography(PolygonM, 4326) +  |  + error: Argument M is out of range for native type `Geography(PolygonZM,4326)` of Postgres: PolygonZM isn't compatible with GeoJson. + --> schema.prisma:59 +  |  + 58 |  geog_09 GeoJson @db.Geography(PolygonM, 4326) + 59 |  geog_10 GeoJson @db.Geography(PolygonZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiPointM,4326)` of Postgres: MultiPointM isn't compatible with GeoJson. + --> schema.prisma:60 +  |  + 59 |  geog_10 GeoJson @db.Geography(PolygonZM, 4326) + 60 |  geog_11 GeoJson @db.Geography(MultiPointM, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiPointZM,4326)` of Postgres: MultiPointZM isn't compatible with GeoJson. + --> schema.prisma:61 +  |  + 60 |  geog_11 GeoJson @db.Geography(MultiPointM, 4326) + 61 |  geog_12 GeoJson @db.Geography(MultiPointZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiLineStringM,4326)` of Postgres: MultiLineStringM isn't compatible with GeoJson. + --> schema.prisma:62 +  |  + 61 |  geog_12 GeoJson @db.Geography(MultiPointZM, 4326) + 62 |  geog_13 GeoJson @db.Geography(MultiLineStringM, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiLineStringZM,4326)` of Postgres: MultiLineStringZM isn't compatible with GeoJson. + --> schema.prisma:63 +  |  + 62 |  geog_13 GeoJson @db.Geography(MultiLineStringM, 4326) + 63 |  geog_14 GeoJson @db.Geography(MultiLineStringZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiPolygonM,4326)` of Postgres: MultiPolygonM isn't compatible with GeoJson. + --> schema.prisma:64 +  |  + 63 |  geog_14 GeoJson @db.Geography(MultiLineStringZM, 4326) + 64 |  geog_15 GeoJson @db.Geography(MultiPolygonM, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiPolygonZM,4326)` of Postgres: MultiPolygonZM isn't compatible with GeoJson. + --> schema.prisma:65 +  |  + 64 |  geog_15 GeoJson @db.Geography(MultiPolygonM, 4326) + 65 |  geog_16 GeoJson @db.Geography(MultiPolygonZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(GeometryCollectionM,4326)` of Postgres: GeometryCollectionM isn't compatible with GeoJson. + --> schema.prisma:66 +  |  + 65 |  geog_16 GeoJson @db.Geography(MultiPolygonZM, 4326) + 66 |  geog_17 GeoJson @db.Geography(GeometryCollectionM, 4326) +  |  + error: Argument M is out of range for native type `Geography(GeometryCollectionZM,4326)` of Postgres: GeometryCollectionZM isn't compatible with GeoJson. + --> schema.prisma:67 +  |  + 66 |  geog_17 GeoJson @db.Geography(GeometryCollectionM, 4326) + 67 |  geog_18 GeoJson @db.Geography(GeometryCollectionZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(CircularString,4326)` of Postgres: CircularString isn't compatible with GeoJson. + --> schema.prisma:68 +  |  + 67 |  geog_18 GeoJson @db.Geography(GeometryCollectionZM, 4326) + 68 |  geog_19 GeoJson @db.Geography(CircularString, 4326) +  |  + error: Argument M is out of range for native type `Geography(CircularStringZ,4326)` of Postgres: CircularStringZ isn't compatible with GeoJson. + --> schema.prisma:69 +  |  + 68 |  geog_19 GeoJson @db.Geography(CircularString, 4326) + 69 |  geog_20 GeoJson @db.Geography(CircularStringZ, 4326) +  |  + error: Argument M is out of range for native type `Geography(CircularStringM,4326)` of Postgres: CircularStringM isn't compatible with GeoJson. + --> schema.prisma:70 +  |  + 69 |  geog_20 GeoJson @db.Geography(CircularStringZ, 4326) + 70 |  geog_21 GeoJson @db.Geography(CircularStringM, 4326) +  |  + error: Argument M is out of range for native type `Geography(CircularStringZM,4326)` of Postgres: CircularStringZM isn't compatible with GeoJson. + --> schema.prisma:71 +  |  + 70 |  geog_21 GeoJson @db.Geography(CircularStringM, 4326) + 71 |  geog_22 GeoJson @db.Geography(CircularStringZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(CompoundCurve,4326)` of Postgres: CompoundCurve isn't compatible with GeoJson. + --> schema.prisma:72 +  |  + 71 |  geog_22 GeoJson @db.Geography(CircularStringZM, 4326) + 72 |  geog_23 GeoJson @db.Geography(CompoundCurve, 4326) +  |  + error: Argument M is out of range for native type `Geography(CompoundCurveZ,4326)` of Postgres: CompoundCurveZ isn't compatible with GeoJson. + --> schema.prisma:73 +  |  + 72 |  geog_23 GeoJson @db.Geography(CompoundCurve, 4326) + 73 |  geog_24 GeoJson @db.Geography(CompoundCurveZ, 4326) +  |  + error: Argument M is out of range for native type `Geography(CompoundCurveM,4326)` of Postgres: CompoundCurveM isn't compatible with GeoJson. + --> schema.prisma:74 +  |  + 73 |  geog_24 GeoJson @db.Geography(CompoundCurveZ, 4326) + 74 |  geog_35 GeoJson @db.Geography(CompoundCurveM, 4326) +  |  + error: Argument M is out of range for native type `Geography(CompoundCurveZM,4326)` of Postgres: CompoundCurveZM isn't compatible with GeoJson. + --> schema.prisma:75 +  |  + 74 |  geog_35 GeoJson @db.Geography(CompoundCurveM, 4326) + 75 |  geog_36 GeoJson @db.Geography(CompoundCurveZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(CurvePolygon,4326)` of Postgres: CurvePolygon isn't compatible with GeoJson. + --> schema.prisma:76 +  |  + 75 |  geog_36 GeoJson @db.Geography(CompoundCurveZM, 4326) + 76 |  geog_37 GeoJson @db.Geography(CurvePolygon, 4326) +  |  + error: Argument M is out of range for native type `Geography(CurvePolygonZ,4326)` of Postgres: CurvePolygonZ isn't compatible with GeoJson. + --> schema.prisma:77 +  |  + 76 |  geog_37 GeoJson @db.Geography(CurvePolygon, 4326) + 77 |  geog_38 GeoJson @db.Geography(CurvePolygonZ, 4326) +  |  + error: Argument M is out of range for native type `Geography(CurvePolygonM,4326)` of Postgres: CurvePolygonM isn't compatible with GeoJson. + --> schema.prisma:78 +  |  + 77 |  geog_38 GeoJson @db.Geography(CurvePolygonZ, 4326) + 78 |  geog_39 GeoJson @db.Geography(CurvePolygonM, 4326) +  |  + error: Argument M is out of range for native type `Geography(CurvePolygonZM,4326)` of Postgres: CurvePolygonZM isn't compatible with GeoJson. + --> schema.prisma:79 +  |  + 78 |  geog_39 GeoJson @db.Geography(CurvePolygonM, 4326) + 79 |  geog_40 GeoJson @db.Geography(CurvePolygonZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiCurve,4326)` of Postgres: MultiCurve isn't compatible with GeoJson. + --> schema.prisma:80 +  |  + 79 |  geog_40 GeoJson @db.Geography(CurvePolygonZM, 4326) + 80 |  geog_41 GeoJson @db.Geography(MultiCurve, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiCurveZ,4326)` of Postgres: MultiCurveZ isn't compatible with GeoJson. + --> schema.prisma:81 +  |  + 80 |  geog_41 GeoJson @db.Geography(MultiCurve, 4326) + 81 |  geog_42 GeoJson @db.Geography(MultiCurveZ, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiCurveM,4326)` of Postgres: MultiCurveM isn't compatible with GeoJson. + --> schema.prisma:82 +  |  + 81 |  geog_42 GeoJson @db.Geography(MultiCurveZ, 4326) + 82 |  geog_43 GeoJson @db.Geography(MultiCurveM, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiCurveZM,4326)` of Postgres: MultiCurveZM isn't compatible with GeoJson. + --> schema.prisma:83 +  |  + 82 |  geog_43 GeoJson @db.Geography(MultiCurveM, 4326) + 83 |  geog_44 GeoJson @db.Geography(MultiCurveZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiSurface,4326)` of Postgres: MultiSurface isn't compatible with GeoJson. + --> schema.prisma:84 +  |  + 83 |  geog_44 GeoJson @db.Geography(MultiCurveZM, 4326) + 84 |  geog_45 GeoJson @db.Geography(MultiSurface, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiSurfaceZ,4326)` of Postgres: MultiSurfaceZ isn't compatible with GeoJson. + --> schema.prisma:85 +  |  + 84 |  geog_45 GeoJson @db.Geography(MultiSurface, 4326) + 85 |  geog_46 GeoJson @db.Geography(MultiSurfaceZ, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiSurfaceM,4326)` of Postgres: MultiSurfaceM isn't compatible with GeoJson. + --> schema.prisma:86 +  |  + 85 |  geog_46 GeoJson @db.Geography(MultiSurfaceZ, 4326) + 86 |  geog_47 GeoJson @db.Geography(MultiSurfaceM, 4326) +  |  + error: Argument M is out of range for native type `Geography(MultiSurfaceZM,4326)` of Postgres: MultiSurfaceZM isn't compatible with GeoJson. + --> schema.prisma:87 +  |  + 86 |  geog_47 GeoJson @db.Geography(MultiSurfaceM, 4326) + 87 |  geog_48 GeoJson @db.Geography(MultiSurfaceZM, 4326) +  |  + error: Argument M is out of range for native type `Geography(PolyhedralSurface,4326)` of Postgres: PolyhedralSurface isn't compatible with GeoJson. + --> schema.prisma:88 +  |  + 87 |  geog_48 GeoJson @db.Geography(MultiSurfaceZM, 4326) + 88 |  geog_49 GeoJson @db.Geography(PolyhedralSurface, 4326) +  |  + error: Argument M is out of range for native type `Geography(PolyhedralSurfaceZ,4326)` of Postgres: PolyhedralSurfaceZ isn't compatible with GeoJson. + --> schema.prisma:89 +  |  + 88 |  geog_49 GeoJson @db.Geography(PolyhedralSurface, 4326) + 89 |  geog_50 GeoJson @db.Geography(PolyhedralSurfaceZ, 4326) +  |  + error: Argument M is out of range for native type `Geography(PolyhedralSurfaceM,4326)` of Postgres: PolyhedralSurfaceM isn't compatible with GeoJson. + --> schema.prisma:90 +  |  + 89 |  geog_50 GeoJson @db.Geography(PolyhedralSurfaceZ, 4326) + 90 |  geog_51 GeoJson @db.Geography(PolyhedralSurfaceM, 4326) +  |  + error: Argument M is out of range for native type `Geography(PolyhedralSurfaceZM,4326)` of Postgres: PolyhedralSurfaceZM isn't compatible with GeoJson. + --> schema.prisma:91 +  |  + 90 |  geog_51 GeoJson @db.Geography(PolyhedralSurfaceM, 4326) + 91 |  geog_52 GeoJson @db.Geography(PolyhedralSurfaceZM, 4326)  |  "#]]; diff --git a/psl/psl/tests/types/sqlite_native_types.rs b/psl/psl/tests/types/sqlite_native_types.rs index c9c4133d3a35..725b429e7ae9 100644 --- a/psl/psl/tests/types/sqlite_native_types.rs +++ b/psl/psl/tests/types/sqlite_native_types.rs @@ -165,30 +165,6 @@ fn should_fail_on_geometry_when_extra_geometry_type() { geom_21 Geometry @db.Geometry(PolyhedralSurfaceZ, 4326) geom_22 Geometry @db.Geometry(PolyhedralSurfaceM, 4326) geom_23 Geometry @db.Geometry(PolyhedralSurfaceZM, 4326) - geog_00 Geometry @db.Geography(CircularString, 4326) - geog_01 Geometry @db.Geography(CircularStringZ, 4326) - geog_02 Geometry @db.Geography(CircularStringM, 4326) - geog_03 Geometry @db.Geography(CircularStringZM, 4326) - geog_04 Geometry @db.Geography(CompoundCurve, 4326) - geog_05 Geometry @db.Geography(CompoundCurveZ, 4326) - geog_06 Geometry @db.Geography(CompoundCurveM, 4326) - geog_07 Geometry @db.Geography(CompoundCurveZM, 4326) - geog_08 Geometry @db.Geography(CurvePolygon, 4326) - geog_09 Geometry @db.Geography(CurvePolygonZ, 4326) - geog_10 Geometry @db.Geography(CurvePolygonM, 4326) - geog_11 Geometry @db.Geography(CurvePolygonZM, 4326) - geog_12 Geometry @db.Geography(MultiCurve, 4326) - geog_13 Geometry @db.Geography(MultiCurveZ, 4326) - geog_14 Geometry @db.Geography(MultiCurveM, 4326) - geog_15 Geometry @db.Geography(MultiCurveZM, 4326) - geog_16 Geometry @db.Geography(MultiSurface, 4326) - geog_17 Geometry @db.Geography(MultiSurfaceZ, 4326) - geog_18 Geometry @db.Geography(MultiSurfaceM, 4326) - geog_19 Geometry @db.Geography(MultiSurfaceZM, 4326) - geog_20 Geometry @db.Geography(PolyhedralSurface, 4326) - geog_21 Geometry @db.Geography(PolyhedralSurfaceZ, 4326) - geog_22 Geometry @db.Geography(PolyhedralSurfaceM, 4326) - geog_23 Geometry @db.Geography(PolyhedralSurfaceZM, 4326) } "#}; @@ -337,149 +313,31 @@ fn should_fail_on_geometry_when_extra_geometry_type() { 30 |  geom_22 Geometry @db.Geometry(PolyhedralSurfaceM, 4326) 31 |  geom_23 Geometry @db.Geometry(PolyhedralSurfaceZM, 4326)  |  + "#]]; + + expect_error(schema, &expectation); +} + +#[test] +fn should_fail_on_geography() { + let schema = indoc! {r#" + datasource db { + provider = "sqlite" + url = "file:test.db" + } + + model User { + id Int @id + geog Geometry @db.Geography + } + "#}; + + let expectation = expect![[r#" error: Native type Geography is not supported for sqlite connector. - --> schema.prisma:32 -  |  - 31 |  geom_23 Geometry @db.Geometry(PolyhedralSurfaceZM, 4326) - 32 |  geog_00 Geometry @db.Geography(CircularString, 4326) -  |  - error: Native type Geography is not supported for sqlite connector. - --> schema.prisma:33 -  |  - 32 |  geog_00 Geometry @db.Geography(CircularString, 4326) - 33 |  geog_01 Geometry @db.Geography(CircularStringZ, 4326) -  |  - error: Native type Geography is not supported for sqlite connector. - --> schema.prisma:34 -  |  - 33 |  geog_01 Geometry @db.Geography(CircularStringZ, 4326) - 34 |  geog_02 Geometry @db.Geography(CircularStringM, 4326) -  |  - error: Native type Geography is not supported for sqlite connector. - --> schema.prisma:35 -  |  - 34 |  geog_02 Geometry @db.Geography(CircularStringM, 4326) - 35 |  geog_03 Geometry @db.Geography(CircularStringZM, 4326) -  |  - error: Native type Geography is not supported for sqlite connector. - --> schema.prisma:36 -  |  - 35 |  geog_03 Geometry @db.Geography(CircularStringZM, 4326) - 36 |  geog_04 Geometry @db.Geography(CompoundCurve, 4326) -  |  - error: Native type Geography is not supported for sqlite connector. - --> schema.prisma:37 -  |  - 36 |  geog_04 Geometry @db.Geography(CompoundCurve, 4326) - 37 |  geog_05 Geometry @db.Geography(CompoundCurveZ, 4326) -  |  - error: Native type Geography is not supported for sqlite connector. - --> schema.prisma:38 -  |  - 37 |  geog_05 Geometry @db.Geography(CompoundCurveZ, 4326) - 38 |  geog_06 Geometry @db.Geography(CompoundCurveM, 4326) -  |  - error: Native type Geography is not supported for sqlite connector. - --> schema.prisma:39 -  |  - 38 |  geog_06 Geometry @db.Geography(CompoundCurveM, 4326) - 39 |  geog_07 Geometry @db.Geography(CompoundCurveZM, 4326) -  |  - error: Native type Geography is not supported for sqlite connector. - --> schema.prisma:40 -  |  - 39 |  geog_07 Geometry @db.Geography(CompoundCurveZM, 4326) - 40 |  geog_08 Geometry @db.Geography(CurvePolygon, 4326) -  |  - error: Native type Geography is not supported for sqlite connector. - --> schema.prisma:41 -  |  - 40 |  geog_08 Geometry @db.Geography(CurvePolygon, 4326) - 41 |  geog_09 Geometry @db.Geography(CurvePolygonZ, 4326) -  |  - error: Native type Geography is not supported for sqlite connector. - --> schema.prisma:42 -  |  - 41 |  geog_09 Geometry @db.Geography(CurvePolygonZ, 4326) - 42 |  geog_10 Geometry @db.Geography(CurvePolygonM, 4326) -  |  - error: Native type Geography is not supported for sqlite connector. - --> schema.prisma:43 -  |  - 42 |  geog_10 Geometry @db.Geography(CurvePolygonM, 4326) - 43 |  geog_11 Geometry @db.Geography(CurvePolygonZM, 4326) -  |  - error: Native type Geography is not supported for sqlite connector. - --> schema.prisma:44 -  |  - 43 |  geog_11 Geometry @db.Geography(CurvePolygonZM, 4326) - 44 |  geog_12 Geometry @db.Geography(MultiCurve, 4326) -  |  - error: Native type Geography is not supported for sqlite connector. - --> schema.prisma:45 -  |  - 44 |  geog_12 Geometry @db.Geography(MultiCurve, 4326) - 45 |  geog_13 Geometry @db.Geography(MultiCurveZ, 4326) -  |  - error: Native type Geography is not supported for sqlite connector. - --> schema.prisma:46 -  |  - 45 |  geog_13 Geometry @db.Geography(MultiCurveZ, 4326) - 46 |  geog_14 Geometry @db.Geography(MultiCurveM, 4326) -  |  - error: Native type Geography is not supported for sqlite connector. - --> schema.prisma:47 -  |  - 46 |  geog_14 Geometry @db.Geography(MultiCurveM, 4326) - 47 |  geog_15 Geometry @db.Geography(MultiCurveZM, 4326) -  |  - error: Native type Geography is not supported for sqlite connector. - --> schema.prisma:48 -  |  - 47 |  geog_15 Geometry @db.Geography(MultiCurveZM, 4326) - 48 |  geog_16 Geometry @db.Geography(MultiSurface, 4326) -  |  - error: Native type Geography is not supported for sqlite connector. - --> schema.prisma:49 -  |  - 48 |  geog_16 Geometry @db.Geography(MultiSurface, 4326) - 49 |  geog_17 Geometry @db.Geography(MultiSurfaceZ, 4326) -  |  - error: Native type Geography is not supported for sqlite connector. - --> schema.prisma:50 -  |  - 49 |  geog_17 Geometry @db.Geography(MultiSurfaceZ, 4326) - 50 |  geog_18 Geometry @db.Geography(MultiSurfaceM, 4326) -  |  - error: Native type Geography is not supported for sqlite connector. - --> schema.prisma:51 -  |  - 50 |  geog_18 Geometry @db.Geography(MultiSurfaceM, 4326) - 51 |  geog_19 Geometry @db.Geography(MultiSurfaceZM, 4326) -  |  - error: Native type Geography is not supported for sqlite connector. - --> schema.prisma:52 -  |  - 51 |  geog_19 Geometry @db.Geography(MultiSurfaceZM, 4326) - 52 |  geog_20 Geometry @db.Geography(PolyhedralSurface, 4326) -  |  - error: Native type Geography is not supported for sqlite connector. - --> schema.prisma:53 -  |  - 52 |  geog_20 Geometry @db.Geography(PolyhedralSurface, 4326) - 53 |  geog_21 Geometry @db.Geography(PolyhedralSurfaceZ, 4326) -  |  - error: Native type Geography is not supported for sqlite connector. - --> schema.prisma:54 -  |  - 53 |  geog_21 Geometry @db.Geography(PolyhedralSurfaceZ, 4326) - 54 |  geog_22 Geometry @db.Geography(PolyhedralSurfaceM, 4326) -  |  - error: Native type Geography is not supported for sqlite connector. - --> schema.prisma:55 + --> schema.prisma:8  |  - 54 |  geog_22 Geometry @db.Geography(PolyhedralSurfaceM, 4326) - 55 |  geog_23 Geometry @db.Geography(PolyhedralSurfaceZM, 4326) +  7 |  id Int @id +  8 |  geog Geometry @db.Geography  |  "#]]; From 0b98b7f8e1b3a75acc4fc202113007d1e5d43489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Wed, 2 Oct 2024 14:28:35 +0200 Subject: [PATCH 050/103] Drop extended types support because of inconsistencies between (and within) vendors --- .../cockroach_datamodel_connector.rs | 5 - .../src/builtin_connectors/geometry.rs | 154 +----- .../sqlite_datamodel_connector.rs | 6 - .../tests/types/cockroachdb_native_types.rs | 355 ------------ psl/psl/tests/types/postgres_native_types.rs | 506 ++---------------- psl/psl/tests/types/sqlite_native_types.rs | 261 ++------- quaint/src/ast/compare.rs | 16 - .../data_types/native_types/postgres.rs | 56 -- .../tests/native_types/postgres.rs | 177 ------ .../describers/postgres_describer_tests.rs | 64 --- 10 files changed, 93 insertions(+), 1507 deletions(-) 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 1394361af914..11a76d022ab0 100644 --- a/psl/psl-core/src/builtin_connectors/cockroach_datamodel_connector.rs +++ b/psl/psl-core/src/builtin_connectors/cockroach_datamodel_connector.rs @@ -228,11 +228,6 @@ impl Connector for CockroachDatamodelConnector { { errors.push_error(error.new_argument_m_out_of_range_error("M can range from 0 to 6.", span)) } - CockroachType::Geometry(Some(g)) | CockroachType::Geography(Some(g)) if g.type_.is_extended() => errors - .push_error(error.new_argument_m_out_of_range_error( - &format!("{} isn't supported for the current connector.", g.type_), - span, - )), CockroachType::Geometry(Some(g)) | CockroachType::Geography(Some(g)) if *scalar_type == ScalarType::GeoJson && !g.type_.is_geojson_compatible() => { diff --git a/psl/psl-core/src/builtin_connectors/geometry.rs b/psl/psl-core/src/builtin_connectors/geometry.rs index 177280b68172..e7607a47ba15 100644 --- a/psl/psl-core/src/builtin_connectors/geometry.rs +++ b/psl/psl-core/src/builtin_connectors/geometry.rs @@ -18,16 +18,6 @@ pub enum GeometryType { MultiLineString = 5, MultiPolygon = 6, GeometryCollection = 7, - CircularString = 8, - CompoundCurve = 9, - CurvePolygon = 10, - MultiCurve = 11, - MultiSurface = 12, - // Curve = 13, - // Surface = 14,, - PolyhedralSurface = 15, - Tin = 16, - Triangle = 17, GeometryZ = 1000, PointZ = 1001, LineStringZ = 1002, @@ -36,16 +26,6 @@ pub enum GeometryType { MultiLineStringZ = 1005, MultiPolygonZ = 1006, GeometryCollectionZ = 1007, - CircularStringZ = 1008, - CompoundCurveZ = 1009, - CurvePolygonZ = 1010, - MultiCurveZ = 1011, - MultiSurfaceZ = 1012, - // CurveZ = 1013, - // SurfaceZ = 1014, - PolyhedralSurfaceZ = 1015, - TinZ = 1016, - TriangleZ = 1017, GeometryM = 2000, PointM = 2001, LineStringM = 2002, @@ -54,16 +34,6 @@ pub enum GeometryType { MultiLineStringM = 2005, MultiPolygonM = 2006, GeometryCollectionM = 2007, - CircularStringM = 2008, - CompoundCurveM = 2009, - CurvePolygonM = 2010, - MultiCurveM = 2011, - MultiSurfaceM = 2012, - // CurveM = 2013, - // SurfaceM = 2014, - PolyhedralSurfaceM = 2015, - TinM = 2016, - TriangleM = 2017, GeometryZM = 3000, PointZM = 3001, LineStringZM = 3002, @@ -72,16 +42,6 @@ pub enum GeometryType { MultiLineStringZM = 3005, MultiPolygonZM = 3006, GeometryCollectionZM = 3007, - CircularStringZM = 3008, - CompoundCurveZM = 3009, - CurvePolygonZM = 3010, - MultiCurveZM = 3011, - MultiSurfaceZM = 3012, - // CurveZM = 3013, - // SurfaceZM = 3014, - PolyhedralSurfaceZM = 3015, - TinZM = 3016, - TriangleZM = 3017, } #[derive(Debug, Default, Clone, Copy, PartialEq, PartialOrd)] @@ -105,12 +65,8 @@ impl fmt::Display for GeometryDimension { } impl GeometryType { - pub fn is_extended(&self) -> bool { - self.as_2d() > Self::GeometryCollection - } - pub fn is_geojson_compatible(&self) -> bool { - !self.is_extended() && self.dimension() <= &GeometryDimension::XYZ + self.dimension() <= &GeometryDimension::XYZ } pub fn as_2d(&self) -> Self { @@ -141,16 +97,6 @@ impl TryFrom for GeometryType { 5 => Ok(Self::MultiLineString), 6 => Ok(Self::MultiPolygon), 7 => Ok(Self::GeometryCollection), - 8 => Ok(Self::CircularString), - 9 => Ok(Self::CompoundCurve), - 10 => Ok(Self::CurvePolygon), - 11 => Ok(Self::MultiCurve), - 12 => Ok(Self::MultiSurface), - // 13 => Ok(Self::Curve), - // 14 => Ok(Self::Surface), - 15 => Ok(Self::PolyhedralSurface), - 16 => Ok(Self::Tin), - 17 => Ok(Self::Triangle), 1000 => Ok(Self::GeometryZ), 1001 => Ok(Self::PointZ), 1002 => Ok(Self::LineStringZ), @@ -159,16 +105,6 @@ impl TryFrom for GeometryType { 1005 => Ok(Self::MultiLineStringZ), 1006 => Ok(Self::MultiPolygonZ), 1007 => Ok(Self::GeometryCollectionZ), - 1008 => Ok(Self::CircularStringZ), - 1009 => Ok(Self::CompoundCurveZ), - 1010 => Ok(Self::CurvePolygonZ), - 1011 => Ok(Self::MultiCurveZ), - 1012 => Ok(Self::MultiSurfaceZ), - // 1013 => Ok(Self::CurveZ), - // 1014 => Ok(Self::SurfaceZ), - 1015 => Ok(Self::PolyhedralSurfaceZ), - 1016 => Ok(Self::TinZ), - 1017 => Ok(Self::TriangleZ), 2000 => Ok(Self::GeometryM), 2001 => Ok(Self::PointM), 2002 => Ok(Self::LineStringM), @@ -177,16 +113,6 @@ impl TryFrom for GeometryType { 2005 => Ok(Self::MultiLineStringM), 2006 => Ok(Self::MultiPolygonM), 2007 => Ok(Self::GeometryCollectionM), - 2008 => Ok(Self::CircularStringM), - 2009 => Ok(Self::CompoundCurveM), - 2010 => Ok(Self::CurvePolygonM), - 2011 => Ok(Self::MultiCurveM), - 2012 => Ok(Self::MultiSurfaceM), - // 2013 => Ok(Self::CurveM), - // 2014 => Ok(Self::SurfaceM), - 2015 => Ok(Self::PolyhedralSurfaceM), - 2016 => Ok(Self::TinM), - 2017 => Ok(Self::TriangleM), 3000 => Ok(Self::GeometryZM), 3001 => Ok(Self::PointZM), 3002 => Ok(Self::LineStringZM), @@ -195,17 +121,7 @@ impl TryFrom for GeometryType { 3005 => Ok(Self::MultiLineStringZM), 3006 => Ok(Self::MultiPolygonZM), 3007 => Ok(Self::GeometryCollectionZM), - 3008 => Ok(Self::CircularStringZM), - 3009 => Ok(Self::CompoundCurveZM), - 3010 => Ok(Self::CurvePolygonZM), - 3011 => Ok(Self::MultiCurveZM), - 3012 => Ok(Self::MultiSurfaceZM), - // 3013 => Ok(Self::CurveZM), - // 3014 => Ok(Self::SurfaceZM), - 3015 => Ok(Self::PolyhedralSurfaceZM), - 3016 => Ok(Self::TinZM), - 3017 => Ok(Self::TriangleZM), - i => Err(format!("Invalid geometry type code: {i}")), + i => Err(format!("Unsupported geometry type code: {i}")), } } } @@ -247,39 +163,7 @@ impl FromStr for GeometryType { "geometrycollectionm" => Ok(GeometryType::GeometryCollectionM), "geometrycollectionz" => Ok(GeometryType::GeometryCollectionZ), "geometrycollectionzm" => Ok(GeometryType::GeometryCollectionZM), - "circularstring" => Ok(GeometryType::CircularString), - "circularstringm" => Ok(GeometryType::CircularStringM), - "circularstringz" => Ok(GeometryType::CircularStringZ), - "circularstringzm" => Ok(GeometryType::CircularStringZM), - "compoundcurve" => Ok(GeometryType::CompoundCurve), - "compoundcurvem" => Ok(GeometryType::CompoundCurveM), - "compoundcurvez" => Ok(GeometryType::CompoundCurveZ), - "compoundcurvezm" => Ok(GeometryType::CompoundCurveZM), - "curvepolygon" => Ok(GeometryType::CurvePolygon), - "curvepolygonm" => Ok(GeometryType::CurvePolygonM), - "curvepolygonz" => Ok(GeometryType::CurvePolygonZ), - "curvepolygonzm" => Ok(GeometryType::CurvePolygonZM), - "multicurve" => Ok(GeometryType::MultiCurve), - "multicurvem" => Ok(GeometryType::MultiCurveM), - "multicurvez" => Ok(GeometryType::MultiCurveZ), - "multicurvezm" => Ok(GeometryType::MultiCurveZM), - "multisurface" => Ok(GeometryType::MultiSurface), - "multisurfacem" => Ok(GeometryType::MultiSurfaceM), - "multisurfacez" => Ok(GeometryType::MultiSurfaceZ), - "multisurfacezm" => Ok(GeometryType::MultiSurfaceZM), - "polyhedralsurface" => Ok(GeometryType::PolyhedralSurface), - "polyhedralsurfacem" => Ok(GeometryType::PolyhedralSurfaceM), - "polyhedralsurfacez" => Ok(GeometryType::PolyhedralSurfaceZ), - "polyhedralsurfacezm" => Ok(GeometryType::PolyhedralSurfaceZM), - "triangle" => Ok(GeometryType::Triangle), - "trianglem" => Ok(GeometryType::TriangleM), - "trianglez" => Ok(GeometryType::TriangleZ), - "trianglezm" => Ok(GeometryType::TriangleZM), - "tin" => Ok(GeometryType::Tin), - "tinm" => Ok(GeometryType::TinM), - "tinz" => Ok(GeometryType::TinZ), - "tinzm" => Ok(GeometryType::TinZM), - _ => Err(format!("{} is not a valid geometry type.", s)), + _ => Err(format!("Unsupported geometry type: {}.", s)), } } } @@ -319,38 +203,6 @@ impl fmt::Display for GeometryType { GeometryType::GeometryCollectionM => write!(f, "GeometryCollectionM"), GeometryType::GeometryCollectionZ => write!(f, "GeometryCollectionZ"), GeometryType::GeometryCollectionZM => write!(f, "GeometryCollectionZM"), - GeometryType::CircularString => write!(f, "CircularString"), - GeometryType::CircularStringM => write!(f, "CircularStringM"), - GeometryType::CircularStringZ => write!(f, "CircularStringZ"), - GeometryType::CircularStringZM => write!(f, "CircularStringZM"), - GeometryType::CompoundCurve => write!(f, "CompoundCurve"), - GeometryType::CompoundCurveM => write!(f, "CompoundCurveM"), - GeometryType::CompoundCurveZ => write!(f, "CompoundCurveZ"), - GeometryType::CompoundCurveZM => write!(f, "CompoundCurveZM"), - GeometryType::CurvePolygon => write!(f, "CurvePolygon"), - GeometryType::CurvePolygonM => write!(f, "CurvePolygonM"), - GeometryType::CurvePolygonZ => write!(f, "CurvePolygonZ"), - GeometryType::CurvePolygonZM => write!(f, "CurvePolygonZM"), - GeometryType::MultiCurve => write!(f, "MultiCurve"), - GeometryType::MultiCurveM => write!(f, "MultiCurveM"), - GeometryType::MultiCurveZ => write!(f, "MultiCurveZ"), - GeometryType::MultiCurveZM => write!(f, "MultiCurveZM"), - GeometryType::MultiSurface => write!(f, "MultiSurface"), - GeometryType::MultiSurfaceM => write!(f, "MultiSurfaceM"), - GeometryType::MultiSurfaceZ => write!(f, "MultiSurfaceZ"), - GeometryType::MultiSurfaceZM => write!(f, "MultiSurfaceZM"), - GeometryType::PolyhedralSurface => write!(f, "PolyhedralSurface"), - GeometryType::PolyhedralSurfaceM => write!(f, "PolyhedralSurfaceM"), - GeometryType::PolyhedralSurfaceZ => write!(f, "PolyhedralSurfaceZ"), - GeometryType::PolyhedralSurfaceZM => write!(f, "PolyhedralSurfaceZM"), - GeometryType::Triangle => write!(f, "Triangle"), - GeometryType::TriangleM => write!(f, "TriangleM"), - GeometryType::TriangleZ => write!(f, "TriangleZ"), - GeometryType::TriangleZM => write!(f, "TriangleZM"), - GeometryType::Tin => write!(f, "Tin"), - GeometryType::TinM => write!(f, "TinM"), - GeometryType::TinZ => write!(f, "TinZ"), - GeometryType::TinZM => write!(f, "TinZM"), } } } diff --git a/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs b/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs index 52d3bb5155b0..e9450f50fb69 100644 --- a/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs +++ b/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs @@ -144,12 +144,6 @@ impl Connector for SqliteDatamodelConnector { } SQLiteType::Geometry(Some(g)) if g.srid < -1 => errors .push_error(error.new_argument_m_out_of_range_error("SRID must be superior or equal to -1.", span)), - SQLiteType::Geometry(Some(g)) if g.type_.is_extended() => { - errors.push_error(error.new_argument_m_out_of_range_error( - &format!("{} isn't supported for the current connector.", g.type_), - span, - )) - } _ => (), } } diff --git a/psl/psl/tests/types/cockroachdb_native_types.rs b/psl/psl/tests/types/cockroachdb_native_types.rs index 0fb445985dc7..10d9fbad336e 100644 --- a/psl/psl/tests/types/cockroachdb_native_types.rs +++ b/psl/psl/tests/types/cockroachdb_native_types.rs @@ -617,358 +617,3 @@ fn should_fail_on_geometry_when_out_of_bound_srid() { expect_error(schema, &expectation); } - -#[test] -fn should_fail_on_geometry_when_extra_geometry_type() { - let schema = indoc! {r#" - datasource db { - provider = "cockroachdb" - url = env("DATABASE_URL") - } - - model User { - id Int @id - geom_00 Geometry @db.Geometry(CircularString, 4326) - geom_01 Geometry @db.Geometry(CircularStringZ, 4326) - geom_02 Geometry @db.Geometry(CircularStringM, 4326) - geom_03 Geometry @db.Geometry(CircularStringZM, 4326) - geom_04 Geometry @db.Geometry(CompoundCurve, 4326) - geom_05 Geometry @db.Geometry(CompoundCurveZ, 4326) - geom_06 Geometry @db.Geometry(CompoundCurveM, 4326) - geom_07 Geometry @db.Geometry(CompoundCurveZM, 4326) - geom_08 Geometry @db.Geometry(CurvePolygon, 4326) - geom_09 Geometry @db.Geometry(CurvePolygonZ, 4326) - geom_10 Geometry @db.Geometry(CurvePolygonM, 4326) - geom_11 Geometry @db.Geometry(CurvePolygonZM, 4326) - geom_12 Geometry @db.Geometry(MultiCurve, 4326) - geom_13 Geometry @db.Geometry(MultiCurveZ, 4326) - geom_14 Geometry @db.Geometry(MultiCurveM, 4326) - geom_15 Geometry @db.Geometry(MultiCurveZM, 4326) - geom_16 Geometry @db.Geometry(MultiSurface, 4326) - geom_17 Geometry @db.Geometry(MultiSurfaceZ, 4326) - geom_18 Geometry @db.Geometry(MultiSurfaceM, 4326) - geom_19 Geometry @db.Geometry(MultiSurfaceZM, 4326) - geom_20 Geometry @db.Geometry(PolyhedralSurface, 4326) - geom_21 Geometry @db.Geometry(PolyhedralSurfaceZ, 4326) - geom_22 Geometry @db.Geometry(PolyhedralSurfaceM, 4326) - geom_23 Geometry @db.Geometry(PolyhedralSurfaceZM, 4326) - geog_00 Geometry @db.Geography(CircularString, 4326) - geog_01 Geometry @db.Geography(CircularStringZ, 4326) - geog_02 Geometry @db.Geography(CircularStringM, 4326) - geog_03 Geometry @db.Geography(CircularStringZM, 4326) - geog_04 Geometry @db.Geography(CompoundCurve, 4326) - geog_05 Geometry @db.Geography(CompoundCurveZ, 4326) - geog_06 Geometry @db.Geography(CompoundCurveM, 4326) - geog_07 Geometry @db.Geography(CompoundCurveZM, 4326) - geog_08 Geometry @db.Geography(CurvePolygon, 4326) - geog_09 Geometry @db.Geography(CurvePolygonZ, 4326) - geog_10 Geometry @db.Geography(CurvePolygonM, 4326) - geog_11 Geometry @db.Geography(CurvePolygonZM, 4326) - geog_12 Geometry @db.Geography(MultiCurve, 4326) - geog_13 Geometry @db.Geography(MultiCurveZ, 4326) - geog_14 Geometry @db.Geography(MultiCurveM, 4326) - geog_15 Geometry @db.Geography(MultiCurveZM, 4326) - geog_16 Geometry @db.Geography(MultiSurface, 4326) - geog_17 Geometry @db.Geography(MultiSurfaceZ, 4326) - geog_18 Geometry @db.Geography(MultiSurfaceM, 4326) - geog_19 Geometry @db.Geography(MultiSurfaceZM, 4326) - geog_20 Geometry @db.Geography(PolyhedralSurface, 4326) - geog_21 Geometry @db.Geography(PolyhedralSurfaceZ, 4326) - geog_22 Geometry @db.Geography(PolyhedralSurfaceM, 4326) - geog_23 Geometry @db.Geography(PolyhedralSurfaceZM, 4326) - } - "#}; - - let expectation = expect![[r#" - error: Argument M is out of range for native type `Geometry(CircularString,4326)` of CockroachDB: CircularString isn't supported for the current connector. - --> schema.prisma:8 -  |  -  7 |  id Int @id -  8 |  geom_00 Geometry @db.Geometry(CircularString, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CircularStringZ,4326)` of CockroachDB: CircularStringZ isn't supported for the current connector. - --> schema.prisma:9 -  |  -  8 |  geom_00 Geometry @db.Geometry(CircularString, 4326) -  9 |  geom_01 Geometry @db.Geometry(CircularStringZ, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CircularStringM,4326)` of CockroachDB: CircularStringM isn't supported for the current connector. - --> schema.prisma:10 -  |  -  9 |  geom_01 Geometry @db.Geometry(CircularStringZ, 4326) - 10 |  geom_02 Geometry @db.Geometry(CircularStringM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CircularStringZM,4326)` of CockroachDB: CircularStringZM isn't supported for the current connector. - --> schema.prisma:11 -  |  - 10 |  geom_02 Geometry @db.Geometry(CircularStringM, 4326) - 11 |  geom_03 Geometry @db.Geometry(CircularStringZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CompoundCurve,4326)` of CockroachDB: CompoundCurve isn't supported for the current connector. - --> schema.prisma:12 -  |  - 11 |  geom_03 Geometry @db.Geometry(CircularStringZM, 4326) - 12 |  geom_04 Geometry @db.Geometry(CompoundCurve, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CompoundCurveZ,4326)` of CockroachDB: CompoundCurveZ isn't supported for the current connector. - --> schema.prisma:13 -  |  - 12 |  geom_04 Geometry @db.Geometry(CompoundCurve, 4326) - 13 |  geom_05 Geometry @db.Geometry(CompoundCurveZ, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CompoundCurveM,4326)` of CockroachDB: CompoundCurveM isn't supported for the current connector. - --> schema.prisma:14 -  |  - 13 |  geom_05 Geometry @db.Geometry(CompoundCurveZ, 4326) - 14 |  geom_06 Geometry @db.Geometry(CompoundCurveM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CompoundCurveZM,4326)` of CockroachDB: CompoundCurveZM isn't supported for the current connector. - --> schema.prisma:15 -  |  - 14 |  geom_06 Geometry @db.Geometry(CompoundCurveM, 4326) - 15 |  geom_07 Geometry @db.Geometry(CompoundCurveZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CurvePolygon,4326)` of CockroachDB: CurvePolygon isn't supported for the current connector. - --> schema.prisma:16 -  |  - 15 |  geom_07 Geometry @db.Geometry(CompoundCurveZM, 4326) - 16 |  geom_08 Geometry @db.Geometry(CurvePolygon, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CurvePolygonZ,4326)` of CockroachDB: CurvePolygonZ isn't supported for the current connector. - --> schema.prisma:17 -  |  - 16 |  geom_08 Geometry @db.Geometry(CurvePolygon, 4326) - 17 |  geom_09 Geometry @db.Geometry(CurvePolygonZ, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CurvePolygonM,4326)` of CockroachDB: CurvePolygonM isn't supported for the current connector. - --> schema.prisma:18 -  |  - 17 |  geom_09 Geometry @db.Geometry(CurvePolygonZ, 4326) - 18 |  geom_10 Geometry @db.Geometry(CurvePolygonM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CurvePolygonZM,4326)` of CockroachDB: CurvePolygonZM isn't supported for the current connector. - --> schema.prisma:19 -  |  - 18 |  geom_10 Geometry @db.Geometry(CurvePolygonM, 4326) - 19 |  geom_11 Geometry @db.Geometry(CurvePolygonZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiCurve,4326)` of CockroachDB: MultiCurve isn't supported for the current connector. - --> schema.prisma:20 -  |  - 19 |  geom_11 Geometry @db.Geometry(CurvePolygonZM, 4326) - 20 |  geom_12 Geometry @db.Geometry(MultiCurve, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiCurveZ,4326)` of CockroachDB: MultiCurveZ isn't supported for the current connector. - --> schema.prisma:21 -  |  - 20 |  geom_12 Geometry @db.Geometry(MultiCurve, 4326) - 21 |  geom_13 Geometry @db.Geometry(MultiCurveZ, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiCurveM,4326)` of CockroachDB: MultiCurveM isn't supported for the current connector. - --> schema.prisma:22 -  |  - 21 |  geom_13 Geometry @db.Geometry(MultiCurveZ, 4326) - 22 |  geom_14 Geometry @db.Geometry(MultiCurveM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiCurveZM,4326)` of CockroachDB: MultiCurveZM isn't supported for the current connector. - --> schema.prisma:23 -  |  - 22 |  geom_14 Geometry @db.Geometry(MultiCurveM, 4326) - 23 |  geom_15 Geometry @db.Geometry(MultiCurveZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiSurface,4326)` of CockroachDB: MultiSurface isn't supported for the current connector. - --> schema.prisma:24 -  |  - 23 |  geom_15 Geometry @db.Geometry(MultiCurveZM, 4326) - 24 |  geom_16 Geometry @db.Geometry(MultiSurface, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiSurfaceZ,4326)` of CockroachDB: MultiSurfaceZ isn't supported for the current connector. - --> schema.prisma:25 -  |  - 24 |  geom_16 Geometry @db.Geometry(MultiSurface, 4326) - 25 |  geom_17 Geometry @db.Geometry(MultiSurfaceZ, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiSurfaceM,4326)` of CockroachDB: MultiSurfaceM isn't supported for the current connector. - --> schema.prisma:26 -  |  - 25 |  geom_17 Geometry @db.Geometry(MultiSurfaceZ, 4326) - 26 |  geom_18 Geometry @db.Geometry(MultiSurfaceM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiSurfaceZM,4326)` of CockroachDB: MultiSurfaceZM isn't supported for the current connector. - --> schema.prisma:27 -  |  - 26 |  geom_18 Geometry @db.Geometry(MultiSurfaceM, 4326) - 27 |  geom_19 Geometry @db.Geometry(MultiSurfaceZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(PolyhedralSurface,4326)` of CockroachDB: PolyhedralSurface isn't supported for the current connector. - --> schema.prisma:28 -  |  - 27 |  geom_19 Geometry @db.Geometry(MultiSurfaceZM, 4326) - 28 |  geom_20 Geometry @db.Geometry(PolyhedralSurface, 4326) -  |  - error: Argument M is out of range for native type `Geometry(PolyhedralSurfaceZ,4326)` of CockroachDB: PolyhedralSurfaceZ isn't supported for the current connector. - --> schema.prisma:29 -  |  - 28 |  geom_20 Geometry @db.Geometry(PolyhedralSurface, 4326) - 29 |  geom_21 Geometry @db.Geometry(PolyhedralSurfaceZ, 4326) -  |  - error: Argument M is out of range for native type `Geometry(PolyhedralSurfaceM,4326)` of CockroachDB: PolyhedralSurfaceM isn't supported for the current connector. - --> schema.prisma:30 -  |  - 29 |  geom_21 Geometry @db.Geometry(PolyhedralSurfaceZ, 4326) - 30 |  geom_22 Geometry @db.Geometry(PolyhedralSurfaceM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(PolyhedralSurfaceZM,4326)` of CockroachDB: PolyhedralSurfaceZM isn't supported for the current connector. - --> schema.prisma:31 -  |  - 30 |  geom_22 Geometry @db.Geometry(PolyhedralSurfaceM, 4326) - 31 |  geom_23 Geometry @db.Geometry(PolyhedralSurfaceZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(CircularString,4326)` of CockroachDB: CircularString isn't supported for the current connector. - --> schema.prisma:32 -  |  - 31 |  geom_23 Geometry @db.Geometry(PolyhedralSurfaceZM, 4326) - 32 |  geog_00 Geometry @db.Geography(CircularString, 4326) -  |  - error: Argument M is out of range for native type `Geography(CircularStringZ,4326)` of CockroachDB: CircularStringZ isn't supported for the current connector. - --> schema.prisma:33 -  |  - 32 |  geog_00 Geometry @db.Geography(CircularString, 4326) - 33 |  geog_01 Geometry @db.Geography(CircularStringZ, 4326) -  |  - error: Argument M is out of range for native type `Geography(CircularStringM,4326)` of CockroachDB: CircularStringM isn't supported for the current connector. - --> schema.prisma:34 -  |  - 33 |  geog_01 Geometry @db.Geography(CircularStringZ, 4326) - 34 |  geog_02 Geometry @db.Geography(CircularStringM, 4326) -  |  - error: Argument M is out of range for native type `Geography(CircularStringZM,4326)` of CockroachDB: CircularStringZM isn't supported for the current connector. - --> schema.prisma:35 -  |  - 34 |  geog_02 Geometry @db.Geography(CircularStringM, 4326) - 35 |  geog_03 Geometry @db.Geography(CircularStringZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(CompoundCurve,4326)` of CockroachDB: CompoundCurve isn't supported for the current connector. - --> schema.prisma:36 -  |  - 35 |  geog_03 Geometry @db.Geography(CircularStringZM, 4326) - 36 |  geog_04 Geometry @db.Geography(CompoundCurve, 4326) -  |  - error: Argument M is out of range for native type `Geography(CompoundCurveZ,4326)` of CockroachDB: CompoundCurveZ isn't supported for the current connector. - --> schema.prisma:37 -  |  - 36 |  geog_04 Geometry @db.Geography(CompoundCurve, 4326) - 37 |  geog_05 Geometry @db.Geography(CompoundCurveZ, 4326) -  |  - error: Argument M is out of range for native type `Geography(CompoundCurveM,4326)` of CockroachDB: CompoundCurveM isn't supported for the current connector. - --> schema.prisma:38 -  |  - 37 |  geog_05 Geometry @db.Geography(CompoundCurveZ, 4326) - 38 |  geog_06 Geometry @db.Geography(CompoundCurveM, 4326) -  |  - error: Argument M is out of range for native type `Geography(CompoundCurveZM,4326)` of CockroachDB: CompoundCurveZM isn't supported for the current connector. - --> schema.prisma:39 -  |  - 38 |  geog_06 Geometry @db.Geography(CompoundCurveM, 4326) - 39 |  geog_07 Geometry @db.Geography(CompoundCurveZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(CurvePolygon,4326)` of CockroachDB: CurvePolygon isn't supported for the current connector. - --> schema.prisma:40 -  |  - 39 |  geog_07 Geometry @db.Geography(CompoundCurveZM, 4326) - 40 |  geog_08 Geometry @db.Geography(CurvePolygon, 4326) -  |  - error: Argument M is out of range for native type `Geography(CurvePolygonZ,4326)` of CockroachDB: CurvePolygonZ isn't supported for the current connector. - --> schema.prisma:41 -  |  - 40 |  geog_08 Geometry @db.Geography(CurvePolygon, 4326) - 41 |  geog_09 Geometry @db.Geography(CurvePolygonZ, 4326) -  |  - error: Argument M is out of range for native type `Geography(CurvePolygonM,4326)` of CockroachDB: CurvePolygonM isn't supported for the current connector. - --> schema.prisma:42 -  |  - 41 |  geog_09 Geometry @db.Geography(CurvePolygonZ, 4326) - 42 |  geog_10 Geometry @db.Geography(CurvePolygonM, 4326) -  |  - error: Argument M is out of range for native type `Geography(CurvePolygonZM,4326)` of CockroachDB: CurvePolygonZM isn't supported for the current connector. - --> schema.prisma:43 -  |  - 42 |  geog_10 Geometry @db.Geography(CurvePolygonM, 4326) - 43 |  geog_11 Geometry @db.Geography(CurvePolygonZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiCurve,4326)` of CockroachDB: MultiCurve isn't supported for the current connector. - --> schema.prisma:44 -  |  - 43 |  geog_11 Geometry @db.Geography(CurvePolygonZM, 4326) - 44 |  geog_12 Geometry @db.Geography(MultiCurve, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiCurveZ,4326)` of CockroachDB: MultiCurveZ isn't supported for the current connector. - --> schema.prisma:45 -  |  - 44 |  geog_12 Geometry @db.Geography(MultiCurve, 4326) - 45 |  geog_13 Geometry @db.Geography(MultiCurveZ, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiCurveM,4326)` of CockroachDB: MultiCurveM isn't supported for the current connector. - --> schema.prisma:46 -  |  - 45 |  geog_13 Geometry @db.Geography(MultiCurveZ, 4326) - 46 |  geog_14 Geometry @db.Geography(MultiCurveM, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiCurveZM,4326)` of CockroachDB: MultiCurveZM isn't supported for the current connector. - --> schema.prisma:47 -  |  - 46 |  geog_14 Geometry @db.Geography(MultiCurveM, 4326) - 47 |  geog_15 Geometry @db.Geography(MultiCurveZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiSurface,4326)` of CockroachDB: MultiSurface isn't supported for the current connector. - --> schema.prisma:48 -  |  - 47 |  geog_15 Geometry @db.Geography(MultiCurveZM, 4326) - 48 |  geog_16 Geometry @db.Geography(MultiSurface, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiSurfaceZ,4326)` of CockroachDB: MultiSurfaceZ isn't supported for the current connector. - --> schema.prisma:49 -  |  - 48 |  geog_16 Geometry @db.Geography(MultiSurface, 4326) - 49 |  geog_17 Geometry @db.Geography(MultiSurfaceZ, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiSurfaceM,4326)` of CockroachDB: MultiSurfaceM isn't supported for the current connector. - --> schema.prisma:50 -  |  - 49 |  geog_17 Geometry @db.Geography(MultiSurfaceZ, 4326) - 50 |  geog_18 Geometry @db.Geography(MultiSurfaceM, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiSurfaceZM,4326)` of CockroachDB: MultiSurfaceZM isn't supported for the current connector. - --> schema.prisma:51 -  |  - 50 |  geog_18 Geometry @db.Geography(MultiSurfaceM, 4326) - 51 |  geog_19 Geometry @db.Geography(MultiSurfaceZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(PolyhedralSurface,4326)` of CockroachDB: PolyhedralSurface isn't supported for the current connector. - --> schema.prisma:52 -  |  - 51 |  geog_19 Geometry @db.Geography(MultiSurfaceZM, 4326) - 52 |  geog_20 Geometry @db.Geography(PolyhedralSurface, 4326) -  |  - error: Argument M is out of range for native type `Geography(PolyhedralSurfaceZ,4326)` of CockroachDB: PolyhedralSurfaceZ isn't supported for the current connector. - --> schema.prisma:53 -  |  - 52 |  geog_20 Geometry @db.Geography(PolyhedralSurface, 4326) - 53 |  geog_21 Geometry @db.Geography(PolyhedralSurfaceZ, 4326) -  |  - error: Argument M is out of range for native type `Geography(PolyhedralSurfaceM,4326)` of CockroachDB: PolyhedralSurfaceM isn't supported for the current connector. - --> schema.prisma:54 -  |  - 53 |  geog_21 Geometry @db.Geography(PolyhedralSurfaceZ, 4326) - 54 |  geog_22 Geometry @db.Geography(PolyhedralSurfaceM, 4326) -  |  - error: Argument M is out of range for native type `Geography(PolyhedralSurfaceZM,4326)` of CockroachDB: PolyhedralSurfaceZM isn't supported for the current connector. - --> schema.prisma:55 -  |  - 54 |  geog_22 Geometry @db.Geography(PolyhedralSurfaceM, 4326) - 55 |  geog_23 Geometry @db.Geography(PolyhedralSurfaceZM, 4326) -  |  - "#]]; - - expect_error(schema, &expectation); -} diff --git a/psl/psl/tests/types/postgres_native_types.rs b/psl/psl/tests/types/postgres_native_types.rs index 29d9ad4732ef..5b6dc567a70f 100644 --- a/psl/psl/tests/types/postgres_native_types.rs +++ b/psl/psl/tests/types/postgres_native_types.rs @@ -275,38 +275,6 @@ fn postgis_specific_native_types_are_valid() { geom_30 Geometry @db.Geometry(GeometryCollectionZ, 4326) geom_31 Geometry @db.Geometry(GeometryCollectionM, 4326) geom_32 Geometry @db.Geometry(GeometryCollectionZM, 4326) - geom_33 Geometry @db.Geometry(CircularString, 4326) - geom_34 Geometry @db.Geometry(CircularStringZ, 4326) - geom_35 Geometry @db.Geometry(CircularStringM, 4326) - geom_36 Geometry @db.Geometry(CircularStringZM, 4326) - geom_37 Geometry @db.Geometry(CompoundCurve, 4326) - geom_38 Geometry @db.Geometry(CompoundCurveZ, 4326) - geom_39 Geometry @db.Geometry(CompoundCurveM, 4326) - geom_40 Geometry @db.Geometry(CompoundCurveZM, 4326) - geom_41 Geometry @db.Geometry(CurvePolygon, 4326) - geom_42 Geometry @db.Geometry(CurvePolygonZ, 4326) - geom_43 Geometry @db.Geometry(CurvePolygonM, 4326) - geom_44 Geometry @db.Geometry(CurvePolygonZM, 4326) - geom_45 Geometry @db.Geometry(MultiCurve, 4326) - geom_46 Geometry @db.Geometry(MultiCurveZ, 4326) - geom_47 Geometry @db.Geometry(MultiCurveM, 4326) - geom_48 Geometry @db.Geometry(MultiCurveZM, 4326) - geom_49 Geometry @db.Geometry(MultiSurface, 4326) - geom_50 Geometry @db.Geometry(MultiSurfaceZ, 4326) - geom_51 Geometry @db.Geometry(MultiSurfaceM, 4326) - geom_52 Geometry @db.Geometry(MultiSurfaceZM, 4326) - geom_53 Geometry @db.Geometry(PolyhedralSurface, 4326) - geom_54 Geometry @db.Geometry(PolyhedralSurfaceZ, 4326) - geom_55 Geometry @db.Geometry(PolyhedralSurfaceM, 4326) - geom_56 Geometry @db.Geometry(PolyhedralSurfaceZM, 4326) - geom_57 Geometry @db.Geometry(Tin, 4326) - geom_58 Geometry @db.Geometry(TinZ, 4326) - geom_59 Geometry @db.Geometry(TinM, 4326) - geom_60 Geometry @db.Geometry(TinZM, 4326) - geom_61 Geometry @db.Geometry(Triangle, 4326) - geom_62 Geometry @db.Geometry(TriangleZ, 4326) - geom_63 Geometry @db.Geometry(TriangleM, 4326) - geom_64 Geometry @db.Geometry(TriangleZM, 4326) geog_01 Geometry @db.Geography(Geometry, 4326) geog_02 Geometry @db.Geography(GeometryZ, 4326) geog_03 Geometry @db.Geography(GeometryM, 4326) @@ -339,38 +307,6 @@ fn postgis_specific_native_types_are_valid() { geog_30 Geometry @db.Geography(GeometryCollectionZ, 4326) geog_31 Geometry @db.Geography(GeometryCollectionM, 4326) geog_32 Geometry @db.Geography(GeometryCollectionZM, 4326) - geog_33 Geometry @db.Geography(CircularString, 4326) - geog_34 Geometry @db.Geography(CircularStringZ, 4326) - geog_35 Geometry @db.Geography(CircularStringM, 4326) - geog_36 Geometry @db.Geography(CircularStringZM, 4326) - geog_37 Geometry @db.Geography(CompoundCurve, 4326) - geog_38 Geometry @db.Geography(CompoundCurveZ, 4326) - geog_39 Geometry @db.Geography(CompoundCurveM, 4326) - geog_40 Geometry @db.Geography(CompoundCurveZM, 4326) - geog_41 Geometry @db.Geography(CurvePolygon, 4326) - geog_42 Geometry @db.Geography(CurvePolygonZ, 4326) - geog_43 Geometry @db.Geography(CurvePolygonM, 4326) - geog_44 Geometry @db.Geography(CurvePolygonZM, 4326) - geog_45 Geometry @db.Geography(MultiCurve, 4326) - geog_46 Geometry @db.Geography(MultiCurveZ, 4326) - geog_47 Geometry @db.Geography(MultiCurveM, 4326) - geog_48 Geometry @db.Geography(MultiCurveZM, 4326) - geog_49 Geometry @db.Geography(MultiSurface, 4326) - geog_50 Geometry @db.Geography(MultiSurfaceZ, 4326) - geog_51 Geometry @db.Geography(MultiSurfaceM, 4326) - geog_52 Geometry @db.Geography(MultiSurfaceZM, 4326) - geog_53 Geometry @db.Geography(PolyhedralSurface, 4326) - geog_54 Geometry @db.Geography(PolyhedralSurfaceZ, 4326) - geog_55 Geometry @db.Geography(PolyhedralSurfaceM, 4326) - geog_56 Geometry @db.Geography(PolyhedralSurfaceZM, 4326) - geog_57 Geometry @db.Geography(Tin, 4326) - geog_58 Geometry @db.Geography(TinZ, 4326) - geog_59 Geometry @db.Geography(TinM, 4326) - geog_60 Geometry @db.Geography(TinZM, 4326) - geog_61 Geometry @db.Geography(Triangle, 4326) - geog_62 Geometry @db.Geography(TriangleZ, 4326) - geog_63 Geometry @db.Geography(TriangleM, 4326) - geog_64 Geometry @db.Geography(TriangleZM, 4326) } "#}; @@ -405,30 +341,6 @@ fn should_fail_on_geojson_when_incompatible_geometry_type() { geom_16 GeoJson @db.Geometry(MultiPolygonZM, 4326) geom_17 GeoJson @db.Geometry(GeometryCollectionM, 4326) geom_18 GeoJson @db.Geometry(GeometryCollectionZM, 4326) - geom_19 GeoJson @db.Geometry(CircularString, 4326) - geom_20 GeoJson @db.Geometry(CircularStringZ, 4326) - geom_21 GeoJson @db.Geometry(CircularStringM, 4326) - geom_22 GeoJson @db.Geometry(CircularStringZM, 4326) - geom_23 GeoJson @db.Geometry(CompoundCurve, 4326) - geom_24 GeoJson @db.Geometry(CompoundCurveZ, 4326) - geom_35 GeoJson @db.Geometry(CompoundCurveM, 4326) - geom_36 GeoJson @db.Geometry(CompoundCurveZM, 4326) - geom_37 GeoJson @db.Geometry(CurvePolygon, 4326) - geom_38 GeoJson @db.Geometry(CurvePolygonZ, 4326) - geom_39 GeoJson @db.Geometry(CurvePolygonM, 4326) - geom_40 GeoJson @db.Geometry(CurvePolygonZM, 4326) - geom_41 GeoJson @db.Geometry(MultiCurve, 4326) - geom_42 GeoJson @db.Geometry(MultiCurveZ, 4326) - geom_43 GeoJson @db.Geometry(MultiCurveM, 4326) - geom_44 GeoJson @db.Geometry(MultiCurveZM, 4326) - geom_45 GeoJson @db.Geometry(MultiSurface, 4326) - geom_46 GeoJson @db.Geometry(MultiSurfaceZ, 4326) - geom_47 GeoJson @db.Geometry(MultiSurfaceM, 4326) - geom_48 GeoJson @db.Geometry(MultiSurfaceZM, 4326) - geom_49 GeoJson @db.Geometry(PolyhedralSurface, 4326) - geom_50 GeoJson @db.Geometry(PolyhedralSurfaceZ, 4326) - geom_51 GeoJson @db.Geometry(PolyhedralSurfaceM, 4326) - geom_52 GeoJson @db.Geometry(PolyhedralSurfaceZM, 4326) geog_01 GeoJson @db.Geography(GeometryM, 4326) geog_02 GeoJson @db.Geography(GeometryZM, 4326) geog_03 GeoJson @db.Geography(PointM, 4326) @@ -447,30 +359,6 @@ fn should_fail_on_geojson_when_incompatible_geometry_type() { geog_16 GeoJson @db.Geography(MultiPolygonZM, 4326) geog_17 GeoJson @db.Geography(GeometryCollectionM, 4326) geog_18 GeoJson @db.Geography(GeometryCollectionZM, 4326) - geog_19 GeoJson @db.Geography(CircularString, 4326) - geog_20 GeoJson @db.Geography(CircularStringZ, 4326) - geog_21 GeoJson @db.Geography(CircularStringM, 4326) - geog_22 GeoJson @db.Geography(CircularStringZM, 4326) - geog_23 GeoJson @db.Geography(CompoundCurve, 4326) - geog_24 GeoJson @db.Geography(CompoundCurveZ, 4326) - geog_35 GeoJson @db.Geography(CompoundCurveM, 4326) - geog_36 GeoJson @db.Geography(CompoundCurveZM, 4326) - geog_37 GeoJson @db.Geography(CurvePolygon, 4326) - geog_38 GeoJson @db.Geography(CurvePolygonZ, 4326) - geog_39 GeoJson @db.Geography(CurvePolygonM, 4326) - geog_40 GeoJson @db.Geography(CurvePolygonZM, 4326) - geog_41 GeoJson @db.Geography(MultiCurve, 4326) - geog_42 GeoJson @db.Geography(MultiCurveZ, 4326) - geog_43 GeoJson @db.Geography(MultiCurveM, 4326) - geog_44 GeoJson @db.Geography(MultiCurveZM, 4326) - geog_45 GeoJson @db.Geography(MultiSurface, 4326) - geog_46 GeoJson @db.Geography(MultiSurfaceZ, 4326) - geog_47 GeoJson @db.Geography(MultiSurfaceM, 4326) - geog_48 GeoJson @db.Geography(MultiSurfaceZM, 4326) - geog_49 GeoJson @db.Geography(PolyhedralSurface, 4326) - geog_50 GeoJson @db.Geography(PolyhedralSurfaceZ, 4326) - geog_51 GeoJson @db.Geography(PolyhedralSurfaceM, 4326) - geog_52 GeoJson @db.Geography(PolyhedralSurfaceZM, 4326) } "#}; @@ -583,401 +471,113 @@ fn should_fail_on_geojson_when_incompatible_geometry_type() { 24 |  geom_17 GeoJson @db.Geometry(GeometryCollectionM, 4326) 25 |  geom_18 GeoJson @db.Geometry(GeometryCollectionZM, 4326)  |  - error: Argument M is out of range for native type `Geometry(CircularString,4326)` of Postgres: CircularString isn't compatible with GeoJson. + error: Argument M is out of range for native type `Geography(GeometryM,4326)` of Postgres: GeometryM isn't compatible with GeoJson. --> schema.prisma:26  |  25 |  geom_18 GeoJson @db.Geometry(GeometryCollectionZM, 4326) - 26 |  geom_19 GeoJson @db.Geometry(CircularString, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CircularStringZ,4326)` of Postgres: CircularStringZ isn't compatible with GeoJson. - --> schema.prisma:27 -  |  - 26 |  geom_19 GeoJson @db.Geometry(CircularString, 4326) - 27 |  geom_20 GeoJson @db.Geometry(CircularStringZ, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CircularStringM,4326)` of Postgres: CircularStringM isn't compatible with GeoJson. - --> schema.prisma:28 -  |  - 27 |  geom_20 GeoJson @db.Geometry(CircularStringZ, 4326) - 28 |  geom_21 GeoJson @db.Geometry(CircularStringM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CircularStringZM,4326)` of Postgres: CircularStringZM isn't compatible with GeoJson. - --> schema.prisma:29 -  |  - 28 |  geom_21 GeoJson @db.Geometry(CircularStringM, 4326) - 29 |  geom_22 GeoJson @db.Geometry(CircularStringZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CompoundCurve,4326)` of Postgres: CompoundCurve isn't compatible with GeoJson. - --> schema.prisma:30 -  |  - 29 |  geom_22 GeoJson @db.Geometry(CircularStringZM, 4326) - 30 |  geom_23 GeoJson @db.Geometry(CompoundCurve, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CompoundCurveZ,4326)` of Postgres: CompoundCurveZ isn't compatible with GeoJson. - --> schema.prisma:31 -  |  - 30 |  geom_23 GeoJson @db.Geometry(CompoundCurve, 4326) - 31 |  geom_24 GeoJson @db.Geometry(CompoundCurveZ, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CompoundCurveM,4326)` of Postgres: CompoundCurveM isn't compatible with GeoJson. - --> schema.prisma:32 -  |  - 31 |  geom_24 GeoJson @db.Geometry(CompoundCurveZ, 4326) - 32 |  geom_35 GeoJson @db.Geometry(CompoundCurveM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CompoundCurveZM,4326)` of Postgres: CompoundCurveZM isn't compatible with GeoJson. - --> schema.prisma:33 -  |  - 32 |  geom_35 GeoJson @db.Geometry(CompoundCurveM, 4326) - 33 |  geom_36 GeoJson @db.Geometry(CompoundCurveZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CurvePolygon,4326)` of Postgres: CurvePolygon isn't compatible with GeoJson. - --> schema.prisma:34 -  |  - 33 |  geom_36 GeoJson @db.Geometry(CompoundCurveZM, 4326) - 34 |  geom_37 GeoJson @db.Geometry(CurvePolygon, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CurvePolygonZ,4326)` of Postgres: CurvePolygonZ isn't compatible with GeoJson. - --> schema.prisma:35 -  |  - 34 |  geom_37 GeoJson @db.Geometry(CurvePolygon, 4326) - 35 |  geom_38 GeoJson @db.Geometry(CurvePolygonZ, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CurvePolygonM,4326)` of Postgres: CurvePolygonM isn't compatible with GeoJson. - --> schema.prisma:36 -  |  - 35 |  geom_38 GeoJson @db.Geometry(CurvePolygonZ, 4326) - 36 |  geom_39 GeoJson @db.Geometry(CurvePolygonM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CurvePolygonZM,4326)` of Postgres: CurvePolygonZM isn't compatible with GeoJson. - --> schema.prisma:37 -  |  - 36 |  geom_39 GeoJson @db.Geometry(CurvePolygonM, 4326) - 37 |  geom_40 GeoJson @db.Geometry(CurvePolygonZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiCurve,4326)` of Postgres: MultiCurve isn't compatible with GeoJson. - --> schema.prisma:38 -  |  - 37 |  geom_40 GeoJson @db.Geometry(CurvePolygonZM, 4326) - 38 |  geom_41 GeoJson @db.Geometry(MultiCurve, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiCurveZ,4326)` of Postgres: MultiCurveZ isn't compatible with GeoJson. - --> schema.prisma:39 -  |  - 38 |  geom_41 GeoJson @db.Geometry(MultiCurve, 4326) - 39 |  geom_42 GeoJson @db.Geometry(MultiCurveZ, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiCurveM,4326)` of Postgres: MultiCurveM isn't compatible with GeoJson. - --> schema.prisma:40 -  |  - 39 |  geom_42 GeoJson @db.Geometry(MultiCurveZ, 4326) - 40 |  geom_43 GeoJson @db.Geometry(MultiCurveM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiCurveZM,4326)` of Postgres: MultiCurveZM isn't compatible with GeoJson. - --> schema.prisma:41 -  |  - 40 |  geom_43 GeoJson @db.Geometry(MultiCurveM, 4326) - 41 |  geom_44 GeoJson @db.Geometry(MultiCurveZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiSurface,4326)` of Postgres: MultiSurface isn't compatible with GeoJson. - --> schema.prisma:42 -  |  - 41 |  geom_44 GeoJson @db.Geometry(MultiCurveZM, 4326) - 42 |  geom_45 GeoJson @db.Geometry(MultiSurface, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiSurfaceZ,4326)` of Postgres: MultiSurfaceZ isn't compatible with GeoJson. - --> schema.prisma:43 -  |  - 42 |  geom_45 GeoJson @db.Geometry(MultiSurface, 4326) - 43 |  geom_46 GeoJson @db.Geometry(MultiSurfaceZ, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiSurfaceM,4326)` of Postgres: MultiSurfaceM isn't compatible with GeoJson. - --> schema.prisma:44 -  |  - 43 |  geom_46 GeoJson @db.Geometry(MultiSurfaceZ, 4326) - 44 |  geom_47 GeoJson @db.Geometry(MultiSurfaceM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiSurfaceZM,4326)` of Postgres: MultiSurfaceZM isn't compatible with GeoJson. - --> schema.prisma:45 -  |  - 44 |  geom_47 GeoJson @db.Geometry(MultiSurfaceM, 4326) - 45 |  geom_48 GeoJson @db.Geometry(MultiSurfaceZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(PolyhedralSurface,4326)` of Postgres: PolyhedralSurface isn't compatible with GeoJson. - --> schema.prisma:46 -  |  - 45 |  geom_48 GeoJson @db.Geometry(MultiSurfaceZM, 4326) - 46 |  geom_49 GeoJson @db.Geometry(PolyhedralSurface, 4326) -  |  - error: Argument M is out of range for native type `Geometry(PolyhedralSurfaceZ,4326)` of Postgres: PolyhedralSurfaceZ isn't compatible with GeoJson. - --> schema.prisma:47 -  |  - 46 |  geom_49 GeoJson @db.Geometry(PolyhedralSurface, 4326) - 47 |  geom_50 GeoJson @db.Geometry(PolyhedralSurfaceZ, 4326) -  |  - error: Argument M is out of range for native type `Geometry(PolyhedralSurfaceM,4326)` of Postgres: PolyhedralSurfaceM isn't compatible with GeoJson. - --> schema.prisma:48 -  |  - 47 |  geom_50 GeoJson @db.Geometry(PolyhedralSurfaceZ, 4326) - 48 |  geom_51 GeoJson @db.Geometry(PolyhedralSurfaceM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(PolyhedralSurfaceZM,4326)` of Postgres: PolyhedralSurfaceZM isn't compatible with GeoJson. - --> schema.prisma:49 -  |  - 48 |  geom_51 GeoJson @db.Geometry(PolyhedralSurfaceM, 4326) - 49 |  geom_52 GeoJson @db.Geometry(PolyhedralSurfaceZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(GeometryM,4326)` of Postgres: GeometryM isn't compatible with GeoJson. - --> schema.prisma:50 -  |  - 49 |  geom_52 GeoJson @db.Geometry(PolyhedralSurfaceZM, 4326) - 50 |  geog_01 GeoJson @db.Geography(GeometryM, 4326) + 26 |  geog_01 GeoJson @db.Geography(GeometryM, 4326)  |  error: Argument M is out of range for native type `Geography(GeometryZM,4326)` of Postgres: GeometryZM isn't compatible with GeoJson. - --> schema.prisma:51 + --> schema.prisma:27  |  - 50 |  geog_01 GeoJson @db.Geography(GeometryM, 4326) - 51 |  geog_02 GeoJson @db.Geography(GeometryZM, 4326) + 26 |  geog_01 GeoJson @db.Geography(GeometryM, 4326) + 27 |  geog_02 GeoJson @db.Geography(GeometryZM, 4326)  |  error: Argument M is out of range for native type `Geography(PointM,4326)` of Postgres: PointM isn't compatible with GeoJson. - --> schema.prisma:52 + --> schema.prisma:28  |  - 51 |  geog_02 GeoJson @db.Geography(GeometryZM, 4326) - 52 |  geog_03 GeoJson @db.Geography(PointM, 4326) + 27 |  geog_02 GeoJson @db.Geography(GeometryZM, 4326) + 28 |  geog_03 GeoJson @db.Geography(PointM, 4326)  |  error: Argument M is out of range for native type `Geography(PointZM,4326)` of Postgres: PointZM isn't compatible with GeoJson. - --> schema.prisma:53 + --> schema.prisma:29  |  - 52 |  geog_03 GeoJson @db.Geography(PointM, 4326) - 53 |  geog_04 GeoJson @db.Geography(PointZM, 4326) + 28 |  geog_03 GeoJson @db.Geography(PointM, 4326) + 29 |  geog_04 GeoJson @db.Geography(PointZM, 4326)  |  error: Argument M is out of range for native type `Geography(PointM,4326)` of Postgres: PointM isn't compatible with GeoJson. - --> schema.prisma:54 + --> schema.prisma:30  |  - 53 |  geog_04 GeoJson @db.Geography(PointZM, 4326) - 54 |  geog_05 GeoJson @db.Geography(PointM, 4326) + 29 |  geog_04 GeoJson @db.Geography(PointZM, 4326) + 30 |  geog_05 GeoJson @db.Geography(PointM, 4326)  |  error: Argument M is out of range for native type `Geography(PointZM,4326)` of Postgres: PointZM isn't compatible with GeoJson. - --> schema.prisma:55 + --> schema.prisma:31  |  - 54 |  geog_05 GeoJson @db.Geography(PointM, 4326) - 55 |  geog_06 GeoJson @db.Geography(PointZM, 4326) + 30 |  geog_05 GeoJson @db.Geography(PointM, 4326) + 31 |  geog_06 GeoJson @db.Geography(PointZM, 4326)  |  error: Argument M is out of range for native type `Geography(LineStringM,4326)` of Postgres: LineStringM isn't compatible with GeoJson. - --> schema.prisma:56 + --> schema.prisma:32  |  - 55 |  geog_06 GeoJson @db.Geography(PointZM, 4326) - 56 |  geog_07 GeoJson @db.Geography(LineStringM, 4326) + 31 |  geog_06 GeoJson @db.Geography(PointZM, 4326) + 32 |  geog_07 GeoJson @db.Geography(LineStringM, 4326)  |  error: Argument M is out of range for native type `Geography(LineStringZM,4326)` of Postgres: LineStringZM isn't compatible with GeoJson. - --> schema.prisma:57 + --> schema.prisma:33  |  - 56 |  geog_07 GeoJson @db.Geography(LineStringM, 4326) - 57 |  geog_08 GeoJson @db.Geography(LineStringZM, 4326) + 32 |  geog_07 GeoJson @db.Geography(LineStringM, 4326) + 33 |  geog_08 GeoJson @db.Geography(LineStringZM, 4326)  |  error: Argument M is out of range for native type `Geography(PolygonM,4326)` of Postgres: PolygonM isn't compatible with GeoJson. - --> schema.prisma:58 + --> schema.prisma:34  |  - 57 |  geog_08 GeoJson @db.Geography(LineStringZM, 4326) - 58 |  geog_09 GeoJson @db.Geography(PolygonM, 4326) + 33 |  geog_08 GeoJson @db.Geography(LineStringZM, 4326) + 34 |  geog_09 GeoJson @db.Geography(PolygonM, 4326)  |  error: Argument M is out of range for native type `Geography(PolygonZM,4326)` of Postgres: PolygonZM isn't compatible with GeoJson. - --> schema.prisma:59 + --> schema.prisma:35  |  - 58 |  geog_09 GeoJson @db.Geography(PolygonM, 4326) - 59 |  geog_10 GeoJson @db.Geography(PolygonZM, 4326) + 34 |  geog_09 GeoJson @db.Geography(PolygonM, 4326) + 35 |  geog_10 GeoJson @db.Geography(PolygonZM, 4326)  |  error: Argument M is out of range for native type `Geography(MultiPointM,4326)` of Postgres: MultiPointM isn't compatible with GeoJson. - --> schema.prisma:60 + --> schema.prisma:36  |  - 59 |  geog_10 GeoJson @db.Geography(PolygonZM, 4326) - 60 |  geog_11 GeoJson @db.Geography(MultiPointM, 4326) + 35 |  geog_10 GeoJson @db.Geography(PolygonZM, 4326) + 36 |  geog_11 GeoJson @db.Geography(MultiPointM, 4326)  |  error: Argument M is out of range for native type `Geography(MultiPointZM,4326)` of Postgres: MultiPointZM isn't compatible with GeoJson. - --> schema.prisma:61 + --> schema.prisma:37  |  - 60 |  geog_11 GeoJson @db.Geography(MultiPointM, 4326) - 61 |  geog_12 GeoJson @db.Geography(MultiPointZM, 4326) + 36 |  geog_11 GeoJson @db.Geography(MultiPointM, 4326) + 37 |  geog_12 GeoJson @db.Geography(MultiPointZM, 4326)  |  error: Argument M is out of range for native type `Geography(MultiLineStringM,4326)` of Postgres: MultiLineStringM isn't compatible with GeoJson. - --> schema.prisma:62 + --> schema.prisma:38  |  - 61 |  geog_12 GeoJson @db.Geography(MultiPointZM, 4326) - 62 |  geog_13 GeoJson @db.Geography(MultiLineStringM, 4326) + 37 |  geog_12 GeoJson @db.Geography(MultiPointZM, 4326) + 38 |  geog_13 GeoJson @db.Geography(MultiLineStringM, 4326)  |  error: Argument M is out of range for native type `Geography(MultiLineStringZM,4326)` of Postgres: MultiLineStringZM isn't compatible with GeoJson. - --> schema.prisma:63 + --> schema.prisma:39  |  - 62 |  geog_13 GeoJson @db.Geography(MultiLineStringM, 4326) - 63 |  geog_14 GeoJson @db.Geography(MultiLineStringZM, 4326) + 38 |  geog_13 GeoJson @db.Geography(MultiLineStringM, 4326) + 39 |  geog_14 GeoJson @db.Geography(MultiLineStringZM, 4326)  |  error: Argument M is out of range for native type `Geography(MultiPolygonM,4326)` of Postgres: MultiPolygonM isn't compatible with GeoJson. - --> schema.prisma:64 + --> schema.prisma:40  |  - 63 |  geog_14 GeoJson @db.Geography(MultiLineStringZM, 4326) - 64 |  geog_15 GeoJson @db.Geography(MultiPolygonM, 4326) + 39 |  geog_14 GeoJson @db.Geography(MultiLineStringZM, 4326) + 40 |  geog_15 GeoJson @db.Geography(MultiPolygonM, 4326)  |  error: Argument M is out of range for native type `Geography(MultiPolygonZM,4326)` of Postgres: MultiPolygonZM isn't compatible with GeoJson. - --> schema.prisma:65 + --> schema.prisma:41  |  - 64 |  geog_15 GeoJson @db.Geography(MultiPolygonM, 4326) - 65 |  geog_16 GeoJson @db.Geography(MultiPolygonZM, 4326) + 40 |  geog_15 GeoJson @db.Geography(MultiPolygonM, 4326) + 41 |  geog_16 GeoJson @db.Geography(MultiPolygonZM, 4326)  |  error: Argument M is out of range for native type `Geography(GeometryCollectionM,4326)` of Postgres: GeometryCollectionM isn't compatible with GeoJson. - --> schema.prisma:66 + --> schema.prisma:42  |  - 65 |  geog_16 GeoJson @db.Geography(MultiPolygonZM, 4326) - 66 |  geog_17 GeoJson @db.Geography(GeometryCollectionM, 4326) + 41 |  geog_16 GeoJson @db.Geography(MultiPolygonZM, 4326) + 42 |  geog_17 GeoJson @db.Geography(GeometryCollectionM, 4326)  |  error: Argument M is out of range for native type `Geography(GeometryCollectionZM,4326)` of Postgres: GeometryCollectionZM isn't compatible with GeoJson. - --> schema.prisma:67 -  |  - 66 |  geog_17 GeoJson @db.Geography(GeometryCollectionM, 4326) - 67 |  geog_18 GeoJson @db.Geography(GeometryCollectionZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(CircularString,4326)` of Postgres: CircularString isn't compatible with GeoJson. - --> schema.prisma:68 -  |  - 67 |  geog_18 GeoJson @db.Geography(GeometryCollectionZM, 4326) - 68 |  geog_19 GeoJson @db.Geography(CircularString, 4326) -  |  - error: Argument M is out of range for native type `Geography(CircularStringZ,4326)` of Postgres: CircularStringZ isn't compatible with GeoJson. - --> schema.prisma:69 -  |  - 68 |  geog_19 GeoJson @db.Geography(CircularString, 4326) - 69 |  geog_20 GeoJson @db.Geography(CircularStringZ, 4326) -  |  - error: Argument M is out of range for native type `Geography(CircularStringM,4326)` of Postgres: CircularStringM isn't compatible with GeoJson. - --> schema.prisma:70 -  |  - 69 |  geog_20 GeoJson @db.Geography(CircularStringZ, 4326) - 70 |  geog_21 GeoJson @db.Geography(CircularStringM, 4326) -  |  - error: Argument M is out of range for native type `Geography(CircularStringZM,4326)` of Postgres: CircularStringZM isn't compatible with GeoJson. - --> schema.prisma:71 -  |  - 70 |  geog_21 GeoJson @db.Geography(CircularStringM, 4326) - 71 |  geog_22 GeoJson @db.Geography(CircularStringZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(CompoundCurve,4326)` of Postgres: CompoundCurve isn't compatible with GeoJson. - --> schema.prisma:72 -  |  - 71 |  geog_22 GeoJson @db.Geography(CircularStringZM, 4326) - 72 |  geog_23 GeoJson @db.Geography(CompoundCurve, 4326) -  |  - error: Argument M is out of range for native type `Geography(CompoundCurveZ,4326)` of Postgres: CompoundCurveZ isn't compatible with GeoJson. - --> schema.prisma:73 -  |  - 72 |  geog_23 GeoJson @db.Geography(CompoundCurve, 4326) - 73 |  geog_24 GeoJson @db.Geography(CompoundCurveZ, 4326) -  |  - error: Argument M is out of range for native type `Geography(CompoundCurveM,4326)` of Postgres: CompoundCurveM isn't compatible with GeoJson. - --> schema.prisma:74 -  |  - 73 |  geog_24 GeoJson @db.Geography(CompoundCurveZ, 4326) - 74 |  geog_35 GeoJson @db.Geography(CompoundCurveM, 4326) -  |  - error: Argument M is out of range for native type `Geography(CompoundCurveZM,4326)` of Postgres: CompoundCurveZM isn't compatible with GeoJson. - --> schema.prisma:75 -  |  - 74 |  geog_35 GeoJson @db.Geography(CompoundCurveM, 4326) - 75 |  geog_36 GeoJson @db.Geography(CompoundCurveZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(CurvePolygon,4326)` of Postgres: CurvePolygon isn't compatible with GeoJson. - --> schema.prisma:76 -  |  - 75 |  geog_36 GeoJson @db.Geography(CompoundCurveZM, 4326) - 76 |  geog_37 GeoJson @db.Geography(CurvePolygon, 4326) -  |  - error: Argument M is out of range for native type `Geography(CurvePolygonZ,4326)` of Postgres: CurvePolygonZ isn't compatible with GeoJson. - --> schema.prisma:77 -  |  - 76 |  geog_37 GeoJson @db.Geography(CurvePolygon, 4326) - 77 |  geog_38 GeoJson @db.Geography(CurvePolygonZ, 4326) -  |  - error: Argument M is out of range for native type `Geography(CurvePolygonM,4326)` of Postgres: CurvePolygonM isn't compatible with GeoJson. - --> schema.prisma:78 -  |  - 77 |  geog_38 GeoJson @db.Geography(CurvePolygonZ, 4326) - 78 |  geog_39 GeoJson @db.Geography(CurvePolygonM, 4326) -  |  - error: Argument M is out of range for native type `Geography(CurvePolygonZM,4326)` of Postgres: CurvePolygonZM isn't compatible with GeoJson. - --> schema.prisma:79 -  |  - 78 |  geog_39 GeoJson @db.Geography(CurvePolygonM, 4326) - 79 |  geog_40 GeoJson @db.Geography(CurvePolygonZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiCurve,4326)` of Postgres: MultiCurve isn't compatible with GeoJson. - --> schema.prisma:80 -  |  - 79 |  geog_40 GeoJson @db.Geography(CurvePolygonZM, 4326) - 80 |  geog_41 GeoJson @db.Geography(MultiCurve, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiCurveZ,4326)` of Postgres: MultiCurveZ isn't compatible with GeoJson. - --> schema.prisma:81 -  |  - 80 |  geog_41 GeoJson @db.Geography(MultiCurve, 4326) - 81 |  geog_42 GeoJson @db.Geography(MultiCurveZ, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiCurveM,4326)` of Postgres: MultiCurveM isn't compatible with GeoJson. - --> schema.prisma:82 -  |  - 81 |  geog_42 GeoJson @db.Geography(MultiCurveZ, 4326) - 82 |  geog_43 GeoJson @db.Geography(MultiCurveM, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiCurveZM,4326)` of Postgres: MultiCurveZM isn't compatible with GeoJson. - --> schema.prisma:83 -  |  - 82 |  geog_43 GeoJson @db.Geography(MultiCurveM, 4326) - 83 |  geog_44 GeoJson @db.Geography(MultiCurveZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiSurface,4326)` of Postgres: MultiSurface isn't compatible with GeoJson. - --> schema.prisma:84 -  |  - 83 |  geog_44 GeoJson @db.Geography(MultiCurveZM, 4326) - 84 |  geog_45 GeoJson @db.Geography(MultiSurface, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiSurfaceZ,4326)` of Postgres: MultiSurfaceZ isn't compatible with GeoJson. - --> schema.prisma:85 -  |  - 84 |  geog_45 GeoJson @db.Geography(MultiSurface, 4326) - 85 |  geog_46 GeoJson @db.Geography(MultiSurfaceZ, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiSurfaceM,4326)` of Postgres: MultiSurfaceM isn't compatible with GeoJson. - --> schema.prisma:86 -  |  - 85 |  geog_46 GeoJson @db.Geography(MultiSurfaceZ, 4326) - 86 |  geog_47 GeoJson @db.Geography(MultiSurfaceM, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiSurfaceZM,4326)` of Postgres: MultiSurfaceZM isn't compatible with GeoJson. - --> schema.prisma:87 -  |  - 86 |  geog_47 GeoJson @db.Geography(MultiSurfaceM, 4326) - 87 |  geog_48 GeoJson @db.Geography(MultiSurfaceZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(PolyhedralSurface,4326)` of Postgres: PolyhedralSurface isn't compatible with GeoJson. - --> schema.prisma:88 -  |  - 87 |  geog_48 GeoJson @db.Geography(MultiSurfaceZM, 4326) - 88 |  geog_49 GeoJson @db.Geography(PolyhedralSurface, 4326) -  |  - error: Argument M is out of range for native type `Geography(PolyhedralSurfaceZ,4326)` of Postgres: PolyhedralSurfaceZ isn't compatible with GeoJson. - --> schema.prisma:89 -  |  - 88 |  geog_49 GeoJson @db.Geography(PolyhedralSurface, 4326) - 89 |  geog_50 GeoJson @db.Geography(PolyhedralSurfaceZ, 4326) -  |  - error: Argument M is out of range for native type `Geography(PolyhedralSurfaceM,4326)` of Postgres: PolyhedralSurfaceM isn't compatible with GeoJson. - --> schema.prisma:90 -  |  - 89 |  geog_50 GeoJson @db.Geography(PolyhedralSurfaceZ, 4326) - 90 |  geog_51 GeoJson @db.Geography(PolyhedralSurfaceM, 4326) -  |  - error: Argument M is out of range for native type `Geography(PolyhedralSurfaceZM,4326)` of Postgres: PolyhedralSurfaceZM isn't compatible with GeoJson. - --> schema.prisma:91 + --> schema.prisma:43  |  - 90 |  geog_51 GeoJson @db.Geography(PolyhedralSurfaceM, 4326) - 91 |  geog_52 GeoJson @db.Geography(PolyhedralSurfaceZM, 4326) + 42 |  geog_17 GeoJson @db.Geography(GeometryCollectionM, 4326) + 43 |  geog_18 GeoJson @db.Geography(GeometryCollectionZM, 4326)  |  "#]]; diff --git a/psl/psl/tests/types/sqlite_native_types.rs b/psl/psl/tests/types/sqlite_native_types.rs index 725b429e7ae9..6702e28123bb 100644 --- a/psl/psl/tests/types/sqlite_native_types.rs +++ b/psl/psl/tests/types/sqlite_native_types.rs @@ -10,43 +10,43 @@ fn sqlite_specific_native_types_are_valid() { } model NativeTypesTest { - id Int @id - geomcol1 Geometry @db.Geometry(Geometry, 4326) - geomcol2 Geometry @db.Geometry(GeometryZ, 4326) - geomcol3 Geometry @db.Geometry(GeometryM, 4326) - geomcol4 Geometry @db.Geometry(GeometryZM, 4326) - geomcol5 Geometry @db.Geometry(Point, 4326) - geomcol6 Geometry @db.Geometry(PointZ, 4326) - geomcol7 Geometry @db.Geometry(PointM, 4326) - geomcol8 Geometry @db.Geometry(PointZM, 4326) - geomcol9 Geometry @db.Geometry(Point, 4326) - geomcol10 Geometry @db.Geometry(PointZ, 4326) - geomcol11 Geometry @db.Geometry(PointM, 4326) - geomcol12 Geometry @db.Geometry(PointZM, 4326) - geomcol13 Geometry @db.Geometry(LineString, 4326) - geomcol14 Geometry @db.Geometry(LineStringZ, 4326) - geomcol15 Geometry @db.Geometry(LineStringM, 4326) - geomcol16 Geometry @db.Geometry(LineStringZM, 4326) - geomcol17 Geometry @db.Geometry(Polygon, 4326) - geomcol18 Geometry @db.Geometry(PolygonZ, 4326) - geomcol19 Geometry @db.Geometry(PolygonM, 4326) - geomcol20 Geometry @db.Geometry(PolygonZM, 4326) - geomcol21 Geometry @db.Geometry(MultiPoint, 4326) - geomcol22 Geometry @db.Geometry(MultiPointZ, 4326) - geomcol23 Geometry @db.Geometry(MultiPointM, 4326) - geomcol24 Geometry @db.Geometry(MultiPointZM, 4326) - geomcol25 Geometry @db.Geometry(MultiLineString, 4326) - geomcol26 Geometry @db.Geometry(MultiLineStringZ, 4326) - geomcol27 Geometry @db.Geometry(MultiLineStringM, 4326) - geomcol28 Geometry @db.Geometry(MultiLineStringZM, 4326) - geomcol29 Geometry @db.Geometry(MultiPolygon, 4326) - geomcol30 Geometry @db.Geometry(MultiPolygonZ, 4326) - geomcol31 Geometry @db.Geometry(MultiPolygonM, 4326) - geomcol32 Geometry @db.Geometry(MultiPolygonZM, 4326) - geomcol33 Geometry @db.Geometry(GeometryCollection, 4326) - geomcol34 Geometry @db.Geometry(GeometryCollectionZ, 4326) - geomcol35 Geometry @db.Geometry(GeometryCollectionM, 4326) - geomcol36 Geometry @db.Geometry(GeometryCollectionZM, 4326) + id Int @id + geomcol1 Geometry @db.Geometry(Geometry, 4326) + geomcol2 Geometry @db.Geometry(GeometryZ, 4326) + geomcol3 Geometry @db.Geometry(GeometryM, 4326) + geomcol4 Geometry @db.Geometry(GeometryZM, 4326) + geomcol5 Geometry @db.Geometry(Point, 4326) + geomcol6 Geometry @db.Geometry(PointZ, 4326) + geomcol7 Geometry @db.Geometry(PointM, 4326) + geomcol8 Geometry @db.Geometry(PointZM, 4326) + geomcol9 Geometry @db.Geometry(Point, 4326) + geomcol10 Geometry @db.Geometry(PointZ, 4326) + geomcol11 Geometry @db.Geometry(PointM, 4326) + geomcol12 Geometry @db.Geometry(PointZM, 4326) + geomcol13 Geometry @db.Geometry(LineString, 4326) + geomcol14 Geometry @db.Geometry(LineStringZ, 4326) + geomcol15 Geometry @db.Geometry(LineStringM, 4326) + geomcol16 Geometry @db.Geometry(LineStringZM, 4326) + geomcol17 Geometry @db.Geometry(Polygon, 4326) + geomcol18 Geometry @db.Geometry(PolygonZ, 4326) + geomcol19 Geometry @db.Geometry(PolygonM, 4326) + geomcol20 Geometry @db.Geometry(PolygonZM, 4326) + geomcol21 Geometry @db.Geometry(MultiPoint, 4326) + geomcol22 Geometry @db.Geometry(MultiPointZ, 4326) + geomcol23 Geometry @db.Geometry(MultiPointM, 4326) + geomcol24 Geometry @db.Geometry(MultiPointZM, 4326) + geomcol25 Geometry @db.Geometry(MultiLineString, 4326) + geomcol26 Geometry @db.Geometry(MultiLineStringZ, 4326) + geomcol27 Geometry @db.Geometry(MultiLineStringM, 4326) + geomcol28 Geometry @db.Geometry(MultiLineStringZM, 4326) + geomcol29 Geometry @db.Geometry(MultiPolygon, 4326) + geomcol30 Geometry @db.Geometry(MultiPolygonZ, 4326) + geomcol31 Geometry @db.Geometry(MultiPolygonM, 4326) + geomcol32 Geometry @db.Geometry(MultiPolygonZM, 4326) + geomcol33 Geometry @db.Geometry(GeometryCollection, 4326) + geomcol34 Geometry @db.Geometry(GeometryCollectionZ, 4326) + geomcol35 Geometry @db.Geometry(GeometryCollectionM, 4326) + geomcol36 Geometry @db.Geometry(GeometryCollectionZM, 4326) } "#}; @@ -131,193 +131,6 @@ fn should_fail_on_geometry_when_out_of_bound_srid() { expect_error(schema, &expectation); } -#[test] -fn should_fail_on_geometry_when_extra_geometry_type() { - let schema = indoc! {r#" - datasource db { - provider = "sqlite" - url = "file:test.db" - } - - model User { - id Int @id - geom_00 Geometry @db.Geometry(CircularString, 4326) - geom_01 Geometry @db.Geometry(CircularStringZ, 4326) - geom_02 Geometry @db.Geometry(CircularStringM, 4326) - geom_03 Geometry @db.Geometry(CircularStringZM, 4326) - geom_04 Geometry @db.Geometry(CompoundCurve, 4326) - geom_05 Geometry @db.Geometry(CompoundCurveZ, 4326) - geom_06 Geometry @db.Geometry(CompoundCurveM, 4326) - geom_07 Geometry @db.Geometry(CompoundCurveZM, 4326) - geom_08 Geometry @db.Geometry(CurvePolygon, 4326) - geom_09 Geometry @db.Geometry(CurvePolygonZ, 4326) - geom_10 Geometry @db.Geometry(CurvePolygonM, 4326) - geom_11 Geometry @db.Geometry(CurvePolygonZM, 4326) - geom_12 Geometry @db.Geometry(MultiCurve, 4326) - geom_13 Geometry @db.Geometry(MultiCurveZ, 4326) - geom_14 Geometry @db.Geometry(MultiCurveM, 4326) - geom_15 Geometry @db.Geometry(MultiCurveZM, 4326) - geom_16 Geometry @db.Geometry(MultiSurface, 4326) - geom_17 Geometry @db.Geometry(MultiSurfaceZ, 4326) - geom_18 Geometry @db.Geometry(MultiSurfaceM, 4326) - geom_19 Geometry @db.Geometry(MultiSurfaceZM, 4326) - geom_20 Geometry @db.Geometry(PolyhedralSurface, 4326) - geom_21 Geometry @db.Geometry(PolyhedralSurfaceZ, 4326) - geom_22 Geometry @db.Geometry(PolyhedralSurfaceM, 4326) - geom_23 Geometry @db.Geometry(PolyhedralSurfaceZM, 4326) - } - "#}; - - let expectation = expect![[r#" - error: Argument M is out of range for native type `Geometry(CircularString,4326)` of sqlite: CircularString isn't supported for the current connector. - --> schema.prisma:8 -  |  -  7 |  id Int @id -  8 |  geom_00 Geometry @db.Geometry(CircularString, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CircularStringZ,4326)` of sqlite: CircularStringZ isn't supported for the current connector. - --> schema.prisma:9 -  |  -  8 |  geom_00 Geometry @db.Geometry(CircularString, 4326) -  9 |  geom_01 Geometry @db.Geometry(CircularStringZ, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CircularStringM,4326)` of sqlite: CircularStringM isn't supported for the current connector. - --> schema.prisma:10 -  |  -  9 |  geom_01 Geometry @db.Geometry(CircularStringZ, 4326) - 10 |  geom_02 Geometry @db.Geometry(CircularStringM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CircularStringZM,4326)` of sqlite: CircularStringZM isn't supported for the current connector. - --> schema.prisma:11 -  |  - 10 |  geom_02 Geometry @db.Geometry(CircularStringM, 4326) - 11 |  geom_03 Geometry @db.Geometry(CircularStringZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CompoundCurve,4326)` of sqlite: CompoundCurve isn't supported for the current connector. - --> schema.prisma:12 -  |  - 11 |  geom_03 Geometry @db.Geometry(CircularStringZM, 4326) - 12 |  geom_04 Geometry @db.Geometry(CompoundCurve, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CompoundCurveZ,4326)` of sqlite: CompoundCurveZ isn't supported for the current connector. - --> schema.prisma:13 -  |  - 12 |  geom_04 Geometry @db.Geometry(CompoundCurve, 4326) - 13 |  geom_05 Geometry @db.Geometry(CompoundCurveZ, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CompoundCurveM,4326)` of sqlite: CompoundCurveM isn't supported for the current connector. - --> schema.prisma:14 -  |  - 13 |  geom_05 Geometry @db.Geometry(CompoundCurveZ, 4326) - 14 |  geom_06 Geometry @db.Geometry(CompoundCurveM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CompoundCurveZM,4326)` of sqlite: CompoundCurveZM isn't supported for the current connector. - --> schema.prisma:15 -  |  - 14 |  geom_06 Geometry @db.Geometry(CompoundCurveM, 4326) - 15 |  geom_07 Geometry @db.Geometry(CompoundCurveZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CurvePolygon,4326)` of sqlite: CurvePolygon isn't supported for the current connector. - --> schema.prisma:16 -  |  - 15 |  geom_07 Geometry @db.Geometry(CompoundCurveZM, 4326) - 16 |  geom_08 Geometry @db.Geometry(CurvePolygon, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CurvePolygonZ,4326)` of sqlite: CurvePolygonZ isn't supported for the current connector. - --> schema.prisma:17 -  |  - 16 |  geom_08 Geometry @db.Geometry(CurvePolygon, 4326) - 17 |  geom_09 Geometry @db.Geometry(CurvePolygonZ, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CurvePolygonM,4326)` of sqlite: CurvePolygonM isn't supported for the current connector. - --> schema.prisma:18 -  |  - 17 |  geom_09 Geometry @db.Geometry(CurvePolygonZ, 4326) - 18 |  geom_10 Geometry @db.Geometry(CurvePolygonM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(CurvePolygonZM,4326)` of sqlite: CurvePolygonZM isn't supported for the current connector. - --> schema.prisma:19 -  |  - 18 |  geom_10 Geometry @db.Geometry(CurvePolygonM, 4326) - 19 |  geom_11 Geometry @db.Geometry(CurvePolygonZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiCurve,4326)` of sqlite: MultiCurve isn't supported for the current connector. - --> schema.prisma:20 -  |  - 19 |  geom_11 Geometry @db.Geometry(CurvePolygonZM, 4326) - 20 |  geom_12 Geometry @db.Geometry(MultiCurve, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiCurveZ,4326)` of sqlite: MultiCurveZ isn't supported for the current connector. - --> schema.prisma:21 -  |  - 20 |  geom_12 Geometry @db.Geometry(MultiCurve, 4326) - 21 |  geom_13 Geometry @db.Geometry(MultiCurveZ, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiCurveM,4326)` of sqlite: MultiCurveM isn't supported for the current connector. - --> schema.prisma:22 -  |  - 21 |  geom_13 Geometry @db.Geometry(MultiCurveZ, 4326) - 22 |  geom_14 Geometry @db.Geometry(MultiCurveM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiCurveZM,4326)` of sqlite: MultiCurveZM isn't supported for the current connector. - --> schema.prisma:23 -  |  - 22 |  geom_14 Geometry @db.Geometry(MultiCurveM, 4326) - 23 |  geom_15 Geometry @db.Geometry(MultiCurveZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiSurface,4326)` of sqlite: MultiSurface isn't supported for the current connector. - --> schema.prisma:24 -  |  - 23 |  geom_15 Geometry @db.Geometry(MultiCurveZM, 4326) - 24 |  geom_16 Geometry @db.Geometry(MultiSurface, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiSurfaceZ,4326)` of sqlite: MultiSurfaceZ isn't supported for the current connector. - --> schema.prisma:25 -  |  - 24 |  geom_16 Geometry @db.Geometry(MultiSurface, 4326) - 25 |  geom_17 Geometry @db.Geometry(MultiSurfaceZ, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiSurfaceM,4326)` of sqlite: MultiSurfaceM isn't supported for the current connector. - --> schema.prisma:26 -  |  - 25 |  geom_17 Geometry @db.Geometry(MultiSurfaceZ, 4326) - 26 |  geom_18 Geometry @db.Geometry(MultiSurfaceM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiSurfaceZM,4326)` of sqlite: MultiSurfaceZM isn't supported for the current connector. - --> schema.prisma:27 -  |  - 26 |  geom_18 Geometry @db.Geometry(MultiSurfaceM, 4326) - 27 |  geom_19 Geometry @db.Geometry(MultiSurfaceZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(PolyhedralSurface,4326)` of sqlite: PolyhedralSurface isn't supported for the current connector. - --> schema.prisma:28 -  |  - 27 |  geom_19 Geometry @db.Geometry(MultiSurfaceZM, 4326) - 28 |  geom_20 Geometry @db.Geometry(PolyhedralSurface, 4326) -  |  - error: Argument M is out of range for native type `Geometry(PolyhedralSurfaceZ,4326)` of sqlite: PolyhedralSurfaceZ isn't supported for the current connector. - --> schema.prisma:29 -  |  - 28 |  geom_20 Geometry @db.Geometry(PolyhedralSurface, 4326) - 29 |  geom_21 Geometry @db.Geometry(PolyhedralSurfaceZ, 4326) -  |  - error: Argument M is out of range for native type `Geometry(PolyhedralSurfaceM,4326)` of sqlite: PolyhedralSurfaceM isn't supported for the current connector. - --> schema.prisma:30 -  |  - 29 |  geom_21 Geometry @db.Geometry(PolyhedralSurfaceZ, 4326) - 30 |  geom_22 Geometry @db.Geometry(PolyhedralSurfaceM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(PolyhedralSurfaceZM,4326)` of sqlite: PolyhedralSurfaceZM isn't supported for the current connector. - --> schema.prisma:31 -  |  - 30 |  geom_22 Geometry @db.Geometry(PolyhedralSurfaceM, 4326) - 31 |  geom_23 Geometry @db.Geometry(PolyhedralSurfaceZM, 4326) -  |  - "#]]; - - expect_error(schema, &expectation); -} - #[test] fn should_fail_on_geography() { let schema = indoc! {r#" diff --git a/quaint/src/ast/compare.rs b/quaint/src/ast/compare.rs index 323d9e2e1688..add6e1335a85 100644 --- a/quaint/src/ast/compare.rs +++ b/quaint/src/ast/compare.rs @@ -68,18 +68,10 @@ pub enum GeometryCompare<'a> { pub enum GeometryType<'a> { Point, LineString, - CircularString, - CompoundCurve, Polygon, - CurvePolygon, - Triangle, - Tin, MultiPoint, MultiLineString, - MultiCurve, MultiPolygon, - MultiSurface, - PolyhedralSurface, GeometryCollection, ColumnRef(Box>), } @@ -95,18 +87,10 @@ impl fmt::Display for GeometryType<'_> { match self { Self::Point => f.write_str("Point"), Self::LineString => f.write_str("LineString"), - Self::CircularString => f.write_str("CircularString"), - Self::CompoundCurve => f.write_str("CompoundCurve"), Self::Polygon => f.write_str("Polygon"), - Self::CurvePolygon => f.write_str("CurvePolygon"), - Self::Triangle => f.write_str("Triangle"), - Self::Tin => f.write_str("Tin"), Self::MultiPoint => f.write_str("MultiPoint"), Self::MultiLineString => f.write_str("MultiLineString"), - Self::MultiCurve => f.write_str("MultiCurve"), Self::MultiPolygon => f.write_str("MultiPolygon"), - Self::MultiSurface => f.write_str("MultiSurface"), - Self::PolyhedralSurface => f.write_str("PolyhedralSurface"), Self::GeometryCollection => f.write_str("GeometryCollection"), Self::ColumnRef(_) => f.write_str(""), } diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/postgres.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/postgres.rs index ee7c39713b6d..ccb300d0f676 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/postgres.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/postgres.rs @@ -571,62 +571,6 @@ mod postgres { Ok(()) } - fn schema_extra_geometry() -> String { - let schema = indoc! { - r#"model Model { - @@schema("test") - #id(id, String, @id, @default(cuid())) - geometry_triangle Geometry @test.Geometry(Triangle) - geometry_circularstring Geometry @test.Geometry(CircularString) - geometry_compoundcurve Geometry @test.Geometry(CompoundCurve) - geometry_curvepolygon Geometry @test.Geometry(CurvePolygon) - geometry_multicurve Geometry @test.Geometry(MultiCurve) - geometry_multisurface Geometry @test.Geometry(MultiSurface) - geometry_polyhedral Geometry @test.Geometry(PolyhedralSurfaceZ) - geometry_tin Geometry @test.Geometry(Tin) - }"# - }; - - schema.to_owned() - } - - // "PostGIS extra geometry types" should "work" - #[connector_test( - only(Postgres("16-postgis")), - schema(schema_extra_geometry), - db_schemas("public", "test") - )] - async fn native_extra_geometry(runner: Runner) -> TestResult<()> { - insta::assert_snapshot!( - run_query!(&runner, r#"mutation { - createOneModel( - data: { - geometry_triangle: "TRIANGLE((0 0,1 1,2 0,0 0))" - geometry_circularstring: "CIRCULARSTRING(0 0,4 0,4 4,0 4,0 0)" - geometry_compoundcurve: "COMPOUNDCURVE(CIRCULARSTRING(0 0,1 1,1 0),(1 0,0 1))" - geometry_curvepolygon: "CURVEPOLYGON(CIRCULARSTRING(0 0,4 0,4 4,0 4,0 0),(1 1,3 3,3 1,1 1))" - geometry_multicurve: "MULTICURVE((0 0,5 5),CIRCULARSTRING(4 0,4 4,8 4))" - geometry_multisurface: "MULTISURFACE(CURVEPOLYGON(CIRCULARSTRING(0 0,4 0,4 4,0 4,0 0),(1 1,3 3,3 1,1 1)),((10 10,14 12,11 10,10 10),(11 11,11.5 11,11 11.5,11 11)))" - geometry_polyhedral:"POLYHEDRALSURFACE(((0 0 0,1 0 0,0 1 0,0 0 1,0 0 0)))" - geometry_tin: "TIN(((80 130,50 160,80 70,80 130)),((50 160,10 190,10 70,50 160)),((80 70,50 160,10 70,80 70)),((120 160,120 190,50 160,120 160)),((120 190,10 190,50 160,120 190)))" - } - ) { - geometry_triangle - geometry_circularstring - geometry_compoundcurve - geometry_curvepolygon - geometry_multicurve - geometry_multisurface - geometry_polyhedral - geometry_tin - } - }"#), - @r###"{"data":{"createOneModel":{"geometry_triangle":"TRIANGLE((0 0,1 1,2 0,0 0))","geometry_circularstring":"CIRCULARSTRING(0 0,4 0,4 4,0 4,0 0)","geometry_compoundcurve":"COMPOUNDCURVE(CIRCULARSTRING(0 0,1 1,1 0),(1 0,0 1))","geometry_curvepolygon":"CURVEPOLYGON(CIRCULARSTRING(0 0,4 0,4 4,0 4,0 0),(1 1,3 3,3 1,1 1))","geometry_multicurve":"MULTICURVE((0 0,5 5),CIRCULARSTRING(4 0,4 4,8 4))","geometry_multisurface":"MULTISURFACE(CURVEPOLYGON(CIRCULARSTRING(0 0,4 0,4 4,0 4,0 0),(1 1,3 3,3 1,1 1)),((10 10,14 12,11 10,10 10),(11 11,11.5 11,11 11.5,11 11)))","geometry_polyhedral":"POLYHEDRALSURFACE(((0 0 0,1 0 0,0 1 0,0 0 1,0 0 0)))","geometry_tin":"TIN(((80 130,50 160,80 70,80 130)),((50 160,10 190,10 70,50 160)),((80 70,50 160,10 70,80 70)),((120 160,120 190,50 160,120 160)),((120 190,10 190,50 160,120 190)))"}}}"### - ); - - Ok(()) - } - fn schema_geojson_geometry() -> String { let schema = indoc! { r#"model Model { 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 4fa9270c35d4..77cf8512bae0 100644 --- a/schema-engine/sql-introspection-tests/tests/native_types/postgres.rs +++ b/schema-engine/sql-introspection-tests/tests/native_types/postgres.rs @@ -107,73 +107,6 @@ const GEOMETRY_TYPES: &[(&str, &str)] = &[ ), ]; -const GEOMETRY_EXTRA_TYPES: &[(&str, &str)] = &[ - ("geometry_circularstring", "Geometry(CircularString)"), - ("geometry_circularstringm", "Geometry(CircularStringM)"), - ("geometry_circularstringz", "Geometry(CircularStringZ)"), - ("geometry_circularstringzm", "Geometry(CircularStringZM)"), - ("geometry_compoundcurve", "Geometry(CompoundCurve)"), - ("geometry_compoundcurvem", "Geometry(CompoundCurveM)"), - ("geometry_compoundcurvez", "Geometry(CompoundCurveZ)"), - ("geometry_compoundcurvezm", "Geometry(CompoundCurveZM)"), - ("geometry_curvepolygon", "Geometry(CurvePolygon)"), - ("geometry_curvepolygonm", "Geometry(CurvePolygonM)"), - ("geometry_curvepolygonz", "Geometry(CurvePolygonZ)"), - ("geometry_curvepolygonzm", "Geometry(CurvePolygonZM)"), - ("geometry_multicurve", "Geometry(MultiCurve)"), - ("geometry_multicurvem", "Geometry(MultiCurveM)"), - ("geometry_multicurvez", "Geometry(MultiCurveZ)"), - ("geometry_multicurvezm", "Geometry(MultiCurveZM)"), - ("geometry_multisurface", "Geometry(MultiSurface)"), - ("geometry_multisurfacem", "Geometry(MultiSurfaceM)"), - ("geometry_multisurfacez", "Geometry(MultiSurfaceZ)"), - ("geometry_multisurfacezm", "Geometry(MultiSurfaceZM)"), - ("geometry_polyhedralsurface", "Geometry(PolyhedralSurface)"), - ("geometry_polyhedralsurfacem", "Geometry(PolyhedralSurfaceM)"), - ("geometry_polyhedralsurfacez", "Geometry(PolyhedralSurfaceZ)"), - ("geometry_polyhedralsurfacezm", "Geometry(PolyhedralSurfaceZM)"), - ("geometry_triangle", "Geometry(Triangle)"), - ("geometry_trianglem", "Geometry(TriangleM)"), - ("geometry_trianglez", "Geometry(TriangleZ)"), - ("geometry_trianglezm", "Geometry(TriangleZM)"), - ("geometry_tin", "Geometry(Tin)"), - ("geometry_tinm", "Geometry(TinM)"), - ("geometry_tinz", "Geometry(TinZ)"), - ("geometry_tinzm", "Geometry(TinZM)"), - ("geography_circularstring", "Geography(CircularString, 4326)"), - ("geography_circularstringm", "Geography(CircularStringM, 4326)"), - ("geography_circularstringz", "Geography(CircularStringZ, 4326)"), - ("geography_circularstringzm", "Geography(CircularStringZM, 4326)"), - ("geography_compoundcurve", "Geography(CompoundCurve, 4326)"), - ("geography_compoundcurvem", "Geography(CompoundCurveM, 4326)"), - ("geography_compoundcurvez", "Geography(CompoundCurveZ, 4326)"), - ("geography_compoundcurvezm", "Geography(CompoundCurveZM, 4326)"), - ("geography_curvepolygon", "Geography(CurvePolygon, 4326)"), - ("geography_curvepolygonm", "Geography(CurvePolygonM, 4326)"), - ("geography_curvepolygonz", "Geography(CurvePolygonZ, 4326)"), - ("geography_curvepolygonzm", "Geography(CurvePolygonZM, 4326)"), - ("geography_multicurve", "Geography(MultiCurve, 4326)"), - ("geography_multicurvem", "Geography(MultiCurveM, 4326)"), - ("geography_multicurvez", "Geography(MultiCurveZ, 4326)"), - ("geography_multicurvezm", "Geography(MultiCurveZM, 4326)"), - ("geography_multisurface", "Geography(MultiSurface, 4326)"), - ("geography_multisurfacem", "Geography(MultiSurfaceM, 4326)"), - ("geography_multisurfacez", "Geography(MultiSurfaceZ, 4326)"), - ("geography_multisurfacezm", "Geography(MultiSurfaceZM, 4326)"), - ("geography_polyhedralsurface", "Geography(PolyhedralSurface, 4326)"), - ("geography_polyhedralsurfacem", "Geography(PolyhedralSurfaceM, 4326)"), - ("geography_polyhedralsurfacez", "Geography(PolyhedralSurfaceZ, 4326)"), - ("geography_polyhedralsurfacezm", "Geography(PolyhedralSurfaceZM, 4326)"), - ("geography_triangle", "Geography(Triangle, 4326)"), - ("geography_trianglem", "Geography(TriangleM, 4326)"), - ("geography_trianglez", "Geography(TriangleZ, 4326)"), - ("geography_trianglezm", "Geography(TriangleZM, 4326)"), - ("geography_tin", "Geography(Tin, 4326)"), - ("geography_tinm", "Geography(TinM, 4326)"), - ("geography_tinz", "Geography(TinZ, 4326)"), - ("geography_tinzm", "Geography(TinZM, 4326)"), -]; - #[test_connector(tags(Postgres), exclude(PostGIS, CockroachDb))] async fn native_type_columns_feature_on(api: &mut TestApi) -> TestResult { let columns: Vec = TYPES @@ -356,116 +289,6 @@ async fn native_type_spatial_columns_feature_on(api: &mut TestApi) -> TestResult Ok(()) } -#[test_connector(tags(PostGIS), exclude(CockroachDb))] -async fn native_type_extra_spatial_columns_feature_on(api: &mut TestApi) -> TestResult { - api.raw_cmd("CREATE EXTENSION IF NOT EXISTS postgis").await; - - let columns: Vec = GEOMETRY_EXTRA_TYPES - .iter() - .map(|(name, db_type)| format!("\"{name}\" {db_type} Not Null")) - .collect(); - - api.barrel() - .execute(move |migration| { - migration.create_table("Spatial", move |t| { - t.inject_custom("id Integer Primary Key"); - for column in &columns { - t.inject_custom(column); - } - }); - }) - .await?; - - let types = indoc! {r#" - model Spatial { - id Int @id - geometry_circularstring Geometry @db.Geometry(CircularString) - geometry_circularstringm Geometry @db.Geometry(CircularStringM) - geometry_circularstringz Geometry @db.Geometry(CircularStringZ) - geometry_circularstringzm Geometry @db.Geometry(CircularStringZM) - geometry_compoundcurve Geometry @db.Geometry(CompoundCurve) - geometry_compoundcurvem Geometry @db.Geometry(CompoundCurveM) - geometry_compoundcurvez Geometry @db.Geometry(CompoundCurveZ) - geometry_compoundcurvezm Geometry @db.Geometry(CompoundCurveZM) - geometry_curvepolygon Geometry @db.Geometry(CurvePolygon) - geometry_curvepolygonm Geometry @db.Geometry(CurvePolygonM) - geometry_curvepolygonz Geometry @db.Geometry(CurvePolygonZ) - geometry_curvepolygonzm Geometry @db.Geometry(CurvePolygonZM) - geometry_multicurve Geometry @db.Geometry(MultiCurve) - geometry_multicurvem Geometry @db.Geometry(MultiCurveM) - geometry_multicurvez Geometry @db.Geometry(MultiCurveZ) - geometry_multicurvezm Geometry @db.Geometry(MultiCurveZM) - geometry_multisurface Geometry @db.Geometry(MultiSurface) - geometry_multisurfacem Geometry @db.Geometry(MultiSurfaceM) - geometry_multisurfacez Geometry @db.Geometry(MultiSurfaceZ) - geometry_multisurfacezm Geometry @db.Geometry(MultiSurfaceZM) - geometry_polyhedralsurface Geometry @db.Geometry(PolyhedralSurface) - geometry_polyhedralsurfacem Geometry @db.Geometry(PolyhedralSurfaceM) - geometry_polyhedralsurfacez Geometry @db.Geometry(PolyhedralSurfaceZ) - geometry_polyhedralsurfacezm Geometry @db.Geometry(PolyhedralSurfaceZM) - geometry_triangle Geometry @db.Geometry(Triangle) - geometry_trianglem Geometry @db.Geometry(TriangleM) - geometry_trianglez Geometry @db.Geometry(TriangleZ) - geometry_trianglezm Geometry @db.Geometry(TriangleZM) - geometry_tin Geometry @db.Geometry(Tin) - geometry_tinm Geometry @db.Geometry(TinM) - geometry_tinz Geometry @db.Geometry(TinZ) - geometry_tinzm Geometry @db.Geometry(TinZM) - geography_circularstring Geometry @db.Geography(CircularString, 4326) - geography_circularstringm Geometry @db.Geography(CircularStringM, 4326) - geography_circularstringz Geometry @db.Geography(CircularStringZ, 4326) - geography_circularstringzm Geometry @db.Geography(CircularStringZM, 4326) - geography_compoundcurve Geometry @db.Geography(CompoundCurve, 4326) - geography_compoundcurvem Geometry @db.Geography(CompoundCurveM, 4326) - geography_compoundcurvez Geometry @db.Geography(CompoundCurveZ, 4326) - geography_compoundcurvezm Geometry @db.Geography(CompoundCurveZM, 4326) - geography_curvepolygon Geometry @db.Geography(CurvePolygon, 4326) - geography_curvepolygonm Geometry @db.Geography(CurvePolygonM, 4326) - geography_curvepolygonz Geometry @db.Geography(CurvePolygonZ, 4326) - geography_curvepolygonzm Geometry @db.Geography(CurvePolygonZM, 4326) - geography_multicurve Geometry @db.Geography(MultiCurve, 4326) - geography_multicurvem Geometry @db.Geography(MultiCurveM, 4326) - geography_multicurvez Geometry @db.Geography(MultiCurveZ, 4326) - geography_multicurvezm Geometry @db.Geography(MultiCurveZM, 4326) - geography_multisurface Geometry @db.Geography(MultiSurface, 4326) - geography_multisurfacem Geometry @db.Geography(MultiSurfaceM, 4326) - geography_multisurfacez Geometry @db.Geography(MultiSurfaceZ, 4326) - geography_multisurfacezm Geometry @db.Geography(MultiSurfaceZM, 4326) - geography_polyhedralsurface Geometry @db.Geography(PolyhedralSurface, 4326) - geography_polyhedralsurfacem Geometry @db.Geography(PolyhedralSurfaceM, 4326) - geography_polyhedralsurfacez Geometry @db.Geography(PolyhedralSurfaceZ, 4326) - geography_polyhedralsurfacezm Geometry @db.Geography(PolyhedralSurfaceZM, 4326) - geography_triangle Geometry @db.Geography(Triangle, 4326) - geography_trianglem Geometry @db.Geography(TriangleM, 4326) - geography_trianglez Geometry @db.Geography(TriangleZ, 4326) - geography_trianglezm Geometry @db.Geography(TriangleZM, 4326) - geography_tin Geometry @db.Geography(Tin, 4326) - geography_tinm Geometry @db.Geography(TinM, 4326) - geography_tinz Geometry @db.Geography(TinZ, 4326) - geography_tinzm Geometry @db.Geography(TinZM, 4326) - } - - /// This table contains check constraints and requires additional setup for migrations. Visit https://pris.ly/d/check-constraints for more info. - model spatial_ref_sys { - srid Int @id - auth_name String? @db.VarChar(256) - auth_srid Int? - srtext String? @db.VarChar(2048) - proj4text String? @db.VarChar(2048) - } - "#} - .to_string(); - - let result = api.introspect().await?; - - println!("EXPECTATION: \n {types:#}"); - println!("RESULT: \n {result:#}"); - - api.assert_eq_datamodels(&types, &result); - - Ok(()) -} - #[test_connector(tags(Postgres), exclude(PostGIS, CockroachDb))] async fn native_type_array_columns_feature_on(api: &mut TestApi) -> TestResult { api.barrel() diff --git a/schema-engine/sql-schema-describer/tests/describers/postgres_describer_tests.rs b/schema-engine/sql-schema-describer/tests/describers/postgres_describer_tests.rs index 3c28da38dfab..d386104653ad 100644 --- a/schema-engine/sql-schema-describer/tests/describers/postgres_describer_tests.rs +++ b/schema-engine/sql-schema-describer/tests/describers/postgres_describer_tests.rs @@ -1142,38 +1142,6 @@ fn all_postgis_column_types_must_work(api: TestApi) { geometry_collection_z GEOMETRY(GEOMETRYCOLLECTIONZ, 3857), geometry_collection_m GEOMETRY(GEOMETRYCOLLECTIONM, 3857), geometry_collection_zm GEOMETRY(GEOMETRYCOLLECTIONZM, 3857), - geometry_triangle GEOMETRY(TRIANGLE, 3857), - geometry_triangle_z GEOMETRY(TRIANGLEZ, 3857), - geometry_triangle_m GEOMETRY(TRIANGLEM, 3857), - geometry_triangle_zm GEOMETRY(TRIANGLEZM, 3857), - geometry_circularstring GEOMETRY(CIRCULARSTRING, 3857), - geometry_circularstring_z GEOMETRY(CIRCULARSTRINGZ, 3857), - geometry_circularstring_m GEOMETRY(CIRCULARSTRINGM, 3857), - geometry_circularstring_zm GEOMETRY(CIRCULARSTRINGZM, 3857), - geometry_compoundcurve GEOMETRY(COMPOUNDCURVE, 3857), - geometry_compoundcurve_z GEOMETRY(COMPOUNDCURVEZ, 3857), - geometry_compoundcurve_m GEOMETRY(COMPOUNDCURVEM, 3857), - geometry_compoundcurve_zm GEOMETRY(COMPOUNDCURVEZM, 3857), - geometry_curvepolygon GEOMETRY(CURVEPOLYGON, 3857), - geometry_curvepolygon_z GEOMETRY(CURVEPOLYGONZ, 3857), - geometry_curvepolygon_m GEOMETRY(CURVEPOLYGONM, 3857), - geometry_curvepolygon_zm GEOMETRY(CURVEPOLYGONZM, 3857), - geometry_multicurve GEOMETRY(MULTICURVE, 3857), - geometry_multicurve_z GEOMETRY(MULTICURVEZ, 3857), - geometry_multicurve_m GEOMETRY(MULTICURVEM, 3857), - geometry_multicurve_zm GEOMETRY(MULTICURVEZM, 3857), - geometry_multisurface GEOMETRY(MULTISURFACE, 3857), - geometry_multisurface_z GEOMETRY(MULTISURFACEZ, 3857), - geometry_multisurface_m GEOMETRY(MULTISURFACEM, 3857), - geometry_multisurface_zm GEOMETRY(MULTISURFACEZM, 3857), - geometry_polyhedral GEOMETRY(POLYHEDRALSURFACE, 3857), - geometry_polyhedral_z GEOMETRY(POLYHEDRALSURFACEZ, 3857), - geometry_polyhedral_m GEOMETRY(POLYHEDRALSURFACEM, 3857), - geometry_polyhedral_zm GEOMETRY(POLYHEDRALSURFACEZM, 3857), - geometry_tin GEOMETRY(TIN, 3857), - geometry_tin_z GEOMETRY(TINZ, 3857), - geometry_tin_m GEOMETRY(TINM, 3857), - geometry_tin_zm GEOMETRY(TINZM, 3857), geography_geometry GEOGRAPHY(GEOMETRY, 9000), geography_geometry_z GEOGRAPHY(GEOMETRYZ, 9000), geography_geometry_m GEOGRAPHY(GEOMETRYM, 9000), @@ -1206,38 +1174,6 @@ fn all_postgis_column_types_must_work(api: TestApi) { geography_collection_z GEOGRAPHY(GEOMETRYCOLLECTIONZ, 9000), geography_collection_m GEOGRAPHY(GEOMETRYCOLLECTIONM, 9000), geography_collection_zm GEOGRAPHY(GEOMETRYCOLLECTIONZM, 9000), - geography_triangle GEOGRAPHY(TRIANGLE, 9000), - geography_triangle_z GEOGRAPHY(TRIANGLEZ, 9000), - geography_triangle_m GEOGRAPHY(TRIANGLEM, 9000), - geography_triangle_zm GEOGRAPHY(TRIANGLEZM, 9000), - geography_circularstring GEOGRAPHY(CIRCULARSTRING, 9000), - geography_circularstring_z GEOGRAPHY(CIRCULARSTRINGZ, 9000), - geography_circularstring_m GEOGRAPHY(CIRCULARSTRINGM, 9000), - geography_circularstring_zm GEOGRAPHY(CIRCULARSTRINGZM, 9000), - geography_compoundcurve GEOGRAPHY(COMPOUNDCURVE, 9000), - geography_compoundcurve_z GEOGRAPHY(COMPOUNDCURVEZ, 9000), - geography_compoundcurve_m GEOGRAPHY(COMPOUNDCURVEM, 9000), - geography_compoundcurve_zm GEOGRAPHY(COMPOUNDCURVEZM, 9000), - geography_curvepolygon GEOGRAPHY(CURVEPOLYGON, 9000), - geography_curvepolygon_z GEOGRAPHY(CURVEPOLYGONZ, 9000), - geography_curvepolygon_m GEOGRAPHY(CURVEPOLYGONM, 9000), - geography_curvepolygon_zm GEOGRAPHY(CURVEPOLYGONZM, 9000), - geography_multicurve GEOGRAPHY(MULTICURVE, 9000), - geography_multicurve_z GEOGRAPHY(MULTICURVEZ, 9000), - geography_multicurve_m GEOGRAPHY(MULTICURVEM, 9000), - geography_multicurve_zm GEOGRAPHY(MULTICURVEZM, 9000), - geography_multisurface GEOGRAPHY(MULTISURFACE, 9000), - geography_multisurface_z GEOGRAPHY(MULTISURFACEZ, 9000), - geography_multisurface_m GEOGRAPHY(MULTISURFACEM, 9000), - geography_multisurface_zm GEOGRAPHY(MULTISURFACEZM, 9000), - geography_polyhedral GEOGRAPHY(POLYHEDRALSURFACE, 9000), - geography_polyhedral_z GEOGRAPHY(POLYHEDRALSURFACEZ, 9000), - geography_polyhedral_m GEOGRAPHY(POLYHEDRALSURFACEM, 9000), - geography_polyhedral_zm GEOGRAPHY(POLYHEDRALSURFACEZM, 9000), - geography_tin GEOGRAPHY(TIN, 9000), - geography_tin_z GEOGRAPHY(TINZ, 9000), - geography_tin_m GEOGRAPHY(TINM, 9000), - geography_tin_zm GEOGRAPHY(TINZM, 9000) ); "#; api.raw_cmd(sql); From b5d96de49cdda65b61dbc22d7a058968e4a34672 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Thu, 3 Oct 2024 00:43:22 +0200 Subject: [PATCH 051/103] Minor changes --- query-engine/connectors/sql-query-connector/src/ser_raw.rs | 1 + query-engine/core/src/query_document/parser.rs | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/query-engine/connectors/sql-query-connector/src/ser_raw.rs b/query-engine/connectors/sql-query-connector/src/ser_raw.rs index d49bcc28589b..68ffa4fbf0af 100644 --- a/query-engine/connectors/sql-query-connector/src/ser_raw.rs +++ b/query-engine/connectors/sql-query-connector/src/ser_raw.rs @@ -187,6 +187,7 @@ impl<'a> Serialize for SerializedValue<'a> { ValueType::DateTime(value) => value.map(|value| value.to_rfc3339()).serialize(serializer), ValueType::Date(value) => value.serialize(serializer), ValueType::Time(value) => value.serialize(serializer), + // TODO@geometry ValueType::Geometry(_value) => todo!("Don't know how to serialize Geometry yet"), ValueType::Geography(_value) => todo!("Don't know how to serialize Geography yet"), } diff --git a/query-engine/core/src/query_document/parser.rs b/query-engine/core/src/query_document/parser.rs index f89540ff8ecc..4b93cf20b5b5 100644 --- a/query-engine/core/src/query_document/parser.rs +++ b/query-engine/core/src/query_document/parser.rs @@ -3,7 +3,7 @@ use crate::{executor::get_engine_protocol, schema::*}; use bigdecimal::{BigDecimal, ToPrimitive}; use chrono::prelude::*; use core::fmt; -use geojson::GeoJson; +use geojson::Geometry; use indexmap::{IndexMap, IndexSet}; use query_structure::{DefaultKind, PrismaValue, ValueGeneratorFn}; use std::{borrow::Cow, convert::TryFrom, rc::Rc, str::FromStr}; @@ -544,8 +544,8 @@ impl QueryDocumentParser { Ok(PrismaValue::List(prisma_values)) } - fn parse_geojson(&self, selection_path: &Path, argument_path: &Path, s: &str) -> QueryParserResult { - s.parse::().map_err(|err| { + fn parse_geojson(&self, selection_path: &Path, argument_path: &Path, s: &str) -> QueryParserResult { + s.parse::().map_err(|err| { ValidationError::invalid_argument_value( selection_path.segments(), argument_path.segments(), From f680b3df0c043fa4facf5a9cc36585392a5e2a54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Thu, 3 Oct 2024 11:41:33 +0200 Subject: [PATCH 052/103] Fix WKT to GeoJSON step --- .../connectors/sql-query-connector/src/row.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/query-engine/connectors/sql-query-connector/src/row.rs b/query-engine/connectors/sql-query-connector/src/row.rs index b17b4e6740e2..36d3a3588c96 100644 --- a/query-engine/connectors/sql-query-connector/src/row.rs +++ b/query-engine/connectors/sql-query-connector/src/row.rs @@ -303,12 +303,20 @@ fn row_value_to_prisma_value(p_value: Value, meta: ColumnMetadata<'_>) -> Result // the ewkt string back to geojson. However, per specification, GeoJSON geometries // can only be represented with EPSG:4326 projection. Plus WKT can represent more // spatial types than GeoJSON can, so this operation may fail. - ValueType::Text(Some(ref ewkt)) => match ewkt.starts_with("SRID=0;") || ewkt.starts_with("SRID=4326;") { - true => WktStr(&ewkt[ewkt.find(";").unwrap() + 1..]) + ValueType::Text(Some(ref ewkt)) => { + let wkt_start = if !ewkt.starts_with("SRID=") { + Ok(0) + } else if ewkt.starts_with("SRID=0;") { + Ok(7) + } else if ewkt.starts_with("SRID=4326;") { + Ok(10) + } else { + Err(create_error(&p_value)) + }?; + WktStr(&ewkt[wkt_start..]) .to_json() .map(PrismaValue::GeoJson) - .map_err(|_| create_error(&p_value))?, - false => return Err(create_error(&p_value)), + .map_err(|_| create_error(&p_value))? }, _ => return Err(create_error(&p_value)), }, From 53347bba7e13343984751e422c273a3b72d87e18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Thu, 3 Oct 2024 20:46:32 +0200 Subject: [PATCH 053/103] Drop support for M coordinates and make GeoJSON the only geometry IO format --- libs/prisma-value/src/lib.rs | 2 - prisma-fmt/tests/native_types.rs | 4 +- psl/parser-database/src/attributes/default.rs | 1 - psl/parser-database/src/types.rs | 6 +- .../cockroach_datamodel_connector.rs | 28 +- .../native_types.rs | 4 +- .../src/builtin_connectors/geometry.rs | 74 ---- .../src/builtin_connectors/mongodb.rs | 2 +- .../mongodb/mongodb_types.rs | 4 +- .../mssql_datamodel_connector.rs | 4 +- .../mssql_datamodel_connector/native_types.rs | 4 +- .../mysql_datamodel_connector.rs | 17 +- .../mysql_datamodel_connector/native_types.rs | 16 +- .../postgres_datamodel_connector.rs | 28 +- .../native_types.rs | 4 +- .../sqlite_datamodel_connector.rs | 42 +- .../native_types.rs | 2 +- psl/psl-core/src/datamodel_connector.rs | 8 +- .../src/datamodel_connector/capabilities.rs | 4 +- .../datamodel_connector/empty_connector.rs | 2 +- .../validation_pipeline/validations/fields.rs | 18 +- psl/psl/tests/base/base_types.rs | 4 +- .../tests/types/cockroachdb_native_types.rs | 403 ++---------------- psl/psl/tests/types/mssql_native_types.rs | 62 ++- psl/psl/tests/types/mysql_native_types.rs | 219 ++++------ psl/psl/tests/types/postgres_native_types.rs | 359 ++-------------- psl/psl/tests/types/sqlite_native_types.rs | 74 +--- .../mongodb/invalid_json_usage_in_type.prisma | 12 +- .../src/connector/mysql/native/conversion.rs | 24 +- quaint/src/visitor/mysql.rs | 12 +- .../tests/queries/filters/geometry_filter.rs | 6 +- .../writes/data_types/native_types/mongodb.rs | 2 +- .../writes/data_types/native_types/mysql.rs | 176 ++------ .../data_types/native_types/postgres.rs | 190 ++------- .../data_types/native_types/sql_server.rs | 6 +- .../writes/data_types/native_types/sqlite.rs | 161 +++---- .../writes/top_level_mutations/create.rs | 6 +- .../mongodb-query-connector/src/value.rs | 8 +- .../src/model_extensions/scalar_field.rs | 17 +- .../connectors/sql-query-connector/src/row.rs | 36 +- .../sql-query-connector/src/value.rs | 2 +- .../core/src/query_document/parser.rs | 14 +- query-engine/core/src/response_ir/internal.rs | 8 +- .../src/ast_builders/datamodel_ast_builder.rs | 1 - .../schema_ast_builder/type_renderer.rs | 1 - query-engine/query-structure/src/field/mod.rs | 14 +- .../query-structure/src/field/scalar.rs | 2 +- .../query-structure/src/prisma_value_ext.rs | 5 +- .../graphql/schema_renderer/type_renderer.rs | 2 - .../fields/data_input_mapper/update.rs | 2 +- .../input_types/fields/field_filter_types.rs | 2 +- .../schema/src/build/input_types/mod.rs | 5 +- .../schema/src/build/output_types/field.rs | 5 +- query-engine/schema/src/input_types.rs | 6 +- query-engine/schema/src/output_types.rs | 6 +- query-engine/schema/src/query_schema.rs | 2 - .../src/sql_doc_parser.rs | 2 +- .../src/sql_schema_calculator.rs | 1 - .../describers/postgres_describer_tests.rs | 2 +- 59 files changed, 445 insertions(+), 1688 deletions(-) diff --git a/libs/prisma-value/src/lib.rs b/libs/prisma-value/src/lib.rs index b9bc284cad1f..f25954b29572 100644 --- a/libs/prisma-value/src/lib.rs +++ b/libs/prisma-value/src/lib.rs @@ -29,7 +29,6 @@ pub enum PrismaValue { List(PrismaListValue), Json(String), GeoJson(String), - Geometry(String), /// A collections of key-value pairs constituting an object. #[serde(serialize_with = "serialize_object")] @@ -333,7 +332,6 @@ impl fmt::Display for PrismaValue { PrismaValue::Uuid(x) => x.fmt(f), PrismaValue::Json(x) => x.fmt(f), PrismaValue::GeoJson(x) => x.fmt(f), - PrismaValue::Geometry(x) => x.fmt(f), PrismaValue::BigInt(x) => x.fmt(f), PrismaValue::List(x) => { let as_string = format!("{x:?}"); diff --git a/prisma-fmt/tests/native_types.rs b/prisma-fmt/tests/native_types.rs index b1000b113716..16872931d8dc 100644 --- a/prisma-fmt/tests/native_types.rs +++ b/prisma-fmt/tests/native_types.rs @@ -11,7 +11,7 @@ fn test_native_types_list_on_crdb() { let result = prisma_fmt::native_types(serde_json::to_string(schema).unwrap()); let expected = expect![[ - r#"[{"name":"Bit","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Bool","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Boolean"]},{"name":"Bytes","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Bytes"]},{"name":"Char","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Date","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["DateTime"]},{"name":"Decimal","_number_of_args":0,"_number_of_optional_args":2,"prisma_types":["Decimal"]},{"name":"Float4","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Float"]},{"name":"Float8","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Float"]},{"name":"Inet","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"Int2","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Int"]},{"name":"Int4","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Int"]},{"name":"Int8","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["BigInt"]},{"name":"JsonB","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Json"]},{"name":"Oid","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Int"]},{"name":"CatalogSingleChar","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"String","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Time","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Timestamp","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Timestamptz","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Timetz","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Uuid","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"VarBit","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Geometry","_number_of_args":0,"_number_of_optional_args":2,"prisma_types":["Geometry","GeoJson"]},{"name":"Geography","_number_of_args":0,"_number_of_optional_args":2,"prisma_types":["Geometry","GeoJson"]}]"# + r#"[{"name":"Bit","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Bool","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Boolean"]},{"name":"Bytes","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Bytes"]},{"name":"Char","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Date","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["DateTime"]},{"name":"Decimal","_number_of_args":0,"_number_of_optional_args":2,"prisma_types":["Decimal"]},{"name":"Float4","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Float"]},{"name":"Float8","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Float"]},{"name":"Inet","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"Int2","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Int"]},{"name":"Int4","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Int"]},{"name":"Int8","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["BigInt"]},{"name":"JsonB","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Json"]},{"name":"Oid","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Int"]},{"name":"CatalogSingleChar","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"String","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Time","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Timestamp","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Timestamptz","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Timetz","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Uuid","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"VarBit","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Geometry","_number_of_args":0,"_number_of_optional_args":2,"prisma_types":["Geometry"]},{"name":"Geography","_number_of_args":0,"_number_of_optional_args":2,"prisma_types":["Geometry"]}]"# ]]; expected.assert_eq(&result); } @@ -38,7 +38,7 @@ fn test_native_types_multifile() { let result = prisma_fmt::native_types(serde_json::to_string(schema).unwrap()); let expected = expect![[ - r#"[{"name":"SmallInt","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Int"]},{"name":"Integer","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Int"]},{"name":"BigInt","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["BigInt"]},{"name":"Decimal","_number_of_args":0,"_number_of_optional_args":2,"prisma_types":["Decimal"]},{"name":"Money","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Decimal"]},{"name":"Inet","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"Oid","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Int"]},{"name":"Citext","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"Real","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Float"]},{"name":"DoublePrecision","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Float"]},{"name":"VarChar","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Char","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Text","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"ByteA","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Bytes"]},{"name":"Timestamp","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Timestamptz","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Date","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["DateTime"]},{"name":"Time","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Timetz","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Boolean","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Boolean"]},{"name":"Bit","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"VarBit","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Uuid","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"Xml","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"Json","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Json"]},{"name":"JsonB","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Json"]},{"name":"Geometry","_number_of_args":0,"_number_of_optional_args":2,"prisma_types":["Geometry","GeoJson"]},{"name":"Geography","_number_of_args":0,"_number_of_optional_args":2,"prisma_types":["Geometry","GeoJson"]}]"# + r#"[{"name":"SmallInt","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Int"]},{"name":"Integer","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Int"]},{"name":"BigInt","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["BigInt"]},{"name":"Decimal","_number_of_args":0,"_number_of_optional_args":2,"prisma_types":["Decimal"]},{"name":"Money","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Decimal"]},{"name":"Inet","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"Oid","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Int"]},{"name":"Citext","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"Real","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Float"]},{"name":"DoublePrecision","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Float"]},{"name":"VarChar","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Char","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Text","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"ByteA","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Bytes"]},{"name":"Timestamp","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Timestamptz","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Date","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["DateTime"]},{"name":"Time","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Timetz","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["DateTime"]},{"name":"Boolean","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Boolean"]},{"name":"Bit","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"VarBit","_number_of_args":0,"_number_of_optional_args":1,"prisma_types":["String"]},{"name":"Uuid","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"Xml","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["String"]},{"name":"Json","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Json"]},{"name":"JsonB","_number_of_args":0,"_number_of_optional_args":0,"prisma_types":["Json"]},{"name":"Geometry","_number_of_args":0,"_number_of_optional_args":2,"prisma_types":["Geometry"]},{"name":"Geography","_number_of_args":0,"_number_of_optional_args":2,"prisma_types":["Geometry"]}]"# ]]; expected.assert_eq(&result); } diff --git a/psl/parser-database/src/attributes/default.rs b/psl/parser-database/src/attributes/default.rs index d79de7f24f26..acaa3a5a36af 100644 --- a/psl/parser-database/src/attributes/default.rs +++ b/psl/parser-database/src/attributes/default.rs @@ -158,7 +158,6 @@ fn validate_scalar_default_literal( (ScalarType::String, ast::Expression::StringValue(_, _)) | (ScalarType::Json, ast::Expression::StringValue(_, _)) | (ScalarType::Geometry, ast::Expression::StringValue(_, _)) - | (ScalarType::GeoJson, ast::Expression::StringValue(_, _)) | (ScalarType::Bytes, ast::Expression::StringValue(_, _)) | (ScalarType::Int, ast::Expression::NumericValue(_, _)) | (ScalarType::BigInt, ast::Expression::NumericValue(_, _)) diff --git a/psl/parser-database/src/types.rs b/psl/parser-database/src/types.rs index f067ad48e521..bed1a55fd26e 100644 --- a/psl/parser-database/src/types.rs +++ b/psl/parser-database/src/types.rs @@ -266,7 +266,7 @@ impl ScalarFieldType { /// True if the field's type is Geometry. pub fn is_geometry(self) -> bool { - matches!(self, Self::BuiltInScalar(ScalarType::Geometry | ScalarType::GeoJson)) + matches!(self, Self::BuiltInScalar(ScalarType::Geometry)) } } @@ -1453,7 +1453,6 @@ pub enum ScalarType { Bytes, Decimal, Geometry, - GeoJson, } impl ScalarType { @@ -1470,7 +1469,6 @@ impl ScalarType { ScalarType::Bytes => "Bytes", ScalarType::Decimal => "Decimal", ScalarType::Geometry => "Geometry", - ScalarType::GeoJson => "GeoJson", } } @@ -1492,7 +1490,6 @@ impl ScalarType { "json" => Some(ScalarType::Json), "bytes" => Some(ScalarType::Bytes), "decimal" => Some(ScalarType::Decimal), - "geojson" => Some(ScalarType::GeoJson), "geometry" => Some(ScalarType::Geometry), _ => None, }, @@ -1506,7 +1503,6 @@ impl ScalarType { "Json" => Some(ScalarType::Json), "Bytes" => Some(ScalarType::Bytes), "Decimal" => Some(ScalarType::Decimal), - "GeoJson" => Some(ScalarType::GeoJson), "Geometry" => Some(ScalarType::Geometry), _ => None, }, 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 11a76d022ab0..2967ef88dff9 100644 --- a/psl/psl-core/src/builtin_connectors/cockroach_datamodel_connector.rs +++ b/psl/psl-core/src/builtin_connectors/cockroach_datamodel_connector.rs @@ -46,9 +46,9 @@ const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(Connector Json | JsonFiltering | JsonFilteringArrayPath | - EwktGeometry | - GeoJsonGeometry | + Geometry | GeometryRawRead | + GeometryGeoJsonIO | GeometryFiltering | GeometryExtraDims | GeometryExtraTypes | @@ -92,13 +92,6 @@ const SCALAR_TYPE_DEFAULTS: &[(ScalarType, CockroachType)] = &[ srid: 0, })), ), - ( - ScalarType::GeoJson, - CockroachType::Geometry(Some(GeometryParams { - type_: GeometryType::Geometry, - srid: 0, - })), - ), ]; pub(crate) struct CockroachDatamodelConnector; @@ -200,7 +193,7 @@ impl Connector for CockroachDatamodelConnector { fn validate_native_type_arguments( &self, native_type_instance: &NativeTypeInstance, - scalar_type: &ScalarType, + _scalar_type: &ScalarType, span: ast::Span, errors: &mut Diagnostics, ) { @@ -228,21 +221,6 @@ impl Connector for CockroachDatamodelConnector { { errors.push_error(error.new_argument_m_out_of_range_error("M can range from 0 to 6.", span)) } - CockroachType::Geometry(Some(g)) | CockroachType::Geography(Some(g)) - if *scalar_type == ScalarType::GeoJson && !g.type_.is_geojson_compatible() => - { - errors.push_error( - error.new_argument_m_out_of_range_error( - &format!("{} isn't compatible with GeoJson.", g.type_), - span, - ), - ) - } - CockroachType::Geometry(Some(g)) | CockroachType::Geography(Some(g)) - if *scalar_type == ScalarType::GeoJson && !matches!(g.srid, 0 | 4326) => - { - errors.push_error(error.new_argument_m_out_of_range_error("GeoJson SRID must be 4326.", span)) - } CockroachType::Geometry(Some(g)) | CockroachType::Geography(Some(g)) if g.srid < 0 || g.srid > 999000 => { errors.push_error(error.new_argument_m_out_of_range_error("SRID must be between 0 and 999000.", span)) } diff --git a/psl/psl-core/src/builtin_connectors/cockroach_datamodel_connector/native_types.rs b/psl/psl-core/src/builtin_connectors/cockroach_datamodel_connector/native_types.rs index 06540a7c3189..a7b6266a9359 100644 --- a/psl/psl-core/src/builtin_connectors/cockroach_datamodel_connector/native_types.rs +++ b/psl/psl-core/src/builtin_connectors/cockroach_datamodel_connector/native_types.rs @@ -24,6 +24,6 @@ crate::native_type_definition! { Timetz(Option) -> DateTime, Uuid -> String, VarBit(Option) -> String, - Geometry(Option) -> Geometry | GeoJson, - Geography(Option) -> Geometry | GeoJson, + Geometry(Option) -> Geometry, + Geography(Option) -> Geometry, } diff --git a/psl/psl-core/src/builtin_connectors/geometry.rs b/psl/psl-core/src/builtin_connectors/geometry.rs index e7607a47ba15..a2972cf1fdc3 100644 --- a/psl/psl-core/src/builtin_connectors/geometry.rs +++ b/psl/psl-core/src/builtin_connectors/geometry.rs @@ -26,22 +26,6 @@ pub enum GeometryType { MultiLineStringZ = 1005, MultiPolygonZ = 1006, GeometryCollectionZ = 1007, - GeometryM = 2000, - PointM = 2001, - LineStringM = 2002, - PolygonM = 2003, - MultiPointM = 2004, - MultiLineStringM = 2005, - MultiPolygonM = 2006, - GeometryCollectionM = 2007, - GeometryZM = 3000, - PointZM = 3001, - LineStringZM = 3002, - PolygonZM = 3003, - MultiPointZM = 3004, - MultiLineStringZM = 3005, - MultiPolygonZM = 3006, - GeometryCollectionZM = 3007, } #[derive(Debug, Default, Clone, Copy, PartialEq, PartialOrd)] @@ -49,8 +33,6 @@ pub enum GeometryDimension { #[default] XY, XYZ, - XYM, - XYZM, } impl fmt::Display for GeometryDimension { @@ -58,17 +40,11 @@ impl fmt::Display for GeometryDimension { match self { Self::XY => write!(f, "XY"), Self::XYZ => write!(f, "XYZ"), - Self::XYM => write!(f, "XYM"), - Self::XYZM => write!(f, "XYZM"), } } } impl GeometryType { - pub fn is_geojson_compatible(&self) -> bool { - self.dimension() <= &GeometryDimension::XYZ - } - pub fn as_2d(&self) -> Self { Self::try_from(*self as u32 % 1000).unwrap() } @@ -77,8 +53,6 @@ impl GeometryType { match *self as u32 / 1000 { 0 => &GeometryDimension::XY, 1 => &GeometryDimension::XYZ, - 2 => &GeometryDimension::XYM, - 3 => &GeometryDimension::XYZM, _ => unreachable!(), } } @@ -105,22 +79,6 @@ impl TryFrom for GeometryType { 1005 => Ok(Self::MultiLineStringZ), 1006 => Ok(Self::MultiPolygonZ), 1007 => Ok(Self::GeometryCollectionZ), - 2000 => Ok(Self::GeometryM), - 2001 => Ok(Self::PointM), - 2002 => Ok(Self::LineStringM), - 2003 => Ok(Self::PolygonM), - 2004 => Ok(Self::MultiPointM), - 2005 => Ok(Self::MultiLineStringM), - 2006 => Ok(Self::MultiPolygonM), - 2007 => Ok(Self::GeometryCollectionM), - 3000 => Ok(Self::GeometryZM), - 3001 => Ok(Self::PointZM), - 3002 => Ok(Self::LineStringZM), - 3003 => Ok(Self::PolygonZM), - 3004 => Ok(Self::MultiPointZM), - 3005 => Ok(Self::MultiLineStringZM), - 3006 => Ok(Self::MultiPolygonZM), - 3007 => Ok(Self::GeometryCollectionZM), i => Err(format!("Unsupported geometry type code: {i}")), } } @@ -132,37 +90,21 @@ impl FromStr for GeometryType { fn from_str(s: &str) -> Result { match s.to_lowercase().as_str() { "geometry" => Ok(GeometryType::Geometry), - "geometrym" => Ok(GeometryType::GeometryM), "geometryz" => Ok(GeometryType::GeometryZ), - "geometryzm" => Ok(GeometryType::GeometryZM), "point" => Ok(GeometryType::Point), - "pointm" => Ok(GeometryType::PointM), "pointz" => Ok(GeometryType::PointZ), - "pointzm" => Ok(GeometryType::PointZM), "linestring" => Ok(GeometryType::LineString), - "linestringm" => Ok(GeometryType::LineStringM), "linestringz" => Ok(GeometryType::LineStringZ), - "linestringzm" => Ok(GeometryType::LineStringZM), "polygon" => Ok(GeometryType::Polygon), - "polygonm" => Ok(GeometryType::PolygonM), "polygonz" => Ok(GeometryType::PolygonZ), - "polygonzm" => Ok(GeometryType::PolygonZM), "multipoint" => Ok(GeometryType::MultiPoint), - "multipointm" => Ok(GeometryType::MultiPointM), "multipointz" => Ok(GeometryType::MultiPointZ), - "multipointzm" => Ok(GeometryType::MultiPointZM), "multilinestring" => Ok(GeometryType::MultiLineString), - "multilinestringm" => Ok(GeometryType::MultiLineStringM), "multilinestringz" => Ok(GeometryType::MultiLineStringZ), - "multilinestringzm" => Ok(GeometryType::MultiLineStringZM), "multipolygon" => Ok(GeometryType::MultiPolygon), - "multipolygonm" => Ok(GeometryType::MultiPolygonM), "multipolygonz" => Ok(GeometryType::MultiPolygonZ), - "multipolygonzm" => Ok(GeometryType::MultiPolygonZM), "geometrycollection" => Ok(GeometryType::GeometryCollection), - "geometrycollectionm" => Ok(GeometryType::GeometryCollectionM), "geometrycollectionz" => Ok(GeometryType::GeometryCollectionZ), - "geometrycollectionzm" => Ok(GeometryType::GeometryCollectionZM), _ => Err(format!("Unsupported geometry type: {}.", s)), } } @@ -172,37 +114,21 @@ impl fmt::Display for GeometryType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { GeometryType::Geometry => write!(f, "Geometry"), - GeometryType::GeometryM => write!(f, "GeometryM"), GeometryType::GeometryZ => write!(f, "GeometryZ"), - GeometryType::GeometryZM => write!(f, "GeometryZM"), GeometryType::Point => write!(f, "Point"), - GeometryType::PointM => write!(f, "PointM"), GeometryType::PointZ => write!(f, "PointZ"), - GeometryType::PointZM => write!(f, "PointZM"), GeometryType::LineString => write!(f, "LineString"), - GeometryType::LineStringM => write!(f, "LineStringM"), GeometryType::LineStringZ => write!(f, "LineStringZ"), - GeometryType::LineStringZM => write!(f, "LineStringZM"), GeometryType::Polygon => write!(f, "Polygon"), - GeometryType::PolygonM => write!(f, "PolygonM"), GeometryType::PolygonZ => write!(f, "PolygonZ"), - GeometryType::PolygonZM => write!(f, "PolygonZM"), GeometryType::MultiPoint => write!(f, "MultiPoint"), - GeometryType::MultiPointM => write!(f, "MultiPointM"), GeometryType::MultiPointZ => write!(f, "MultiPointZ"), - GeometryType::MultiPointZM => write!(f, "MultiPointZM"), GeometryType::MultiLineString => write!(f, "MultiLineString"), - GeometryType::MultiLineStringM => write!(f, "MultiLineStringM"), GeometryType::MultiLineStringZ => write!(f, "MultiLineStringZ"), - GeometryType::MultiLineStringZM => write!(f, "MultiLineStringZM"), GeometryType::MultiPolygon => write!(f, "MultiPolygon"), - GeometryType::MultiPolygonM => write!(f, "MultiPolygonM"), GeometryType::MultiPolygonZ => write!(f, "MultiPolygonZ"), - GeometryType::MultiPolygonZM => write!(f, "MultiPolygonZM"), GeometryType::GeometryCollection => write!(f, "GeometryCollection"), - GeometryType::GeometryCollectionM => write!(f, "GeometryCollectionM"), GeometryType::GeometryCollectionZ => write!(f, "GeometryCollectionZ"), - GeometryType::GeometryCollectionZM => write!(f, "GeometryCollectionZM"), } } } diff --git a/psl/psl-core/src/builtin_connectors/mongodb.rs b/psl/psl-core/src/builtin_connectors/mongodb.rs index 0587c33332a4..bec283cff092 100644 --- a/psl/psl-core/src/builtin_connectors/mongodb.rs +++ b/psl/psl-core/src/builtin_connectors/mongodb.rs @@ -17,7 +17,7 @@ use std::result::Result as StdResult; const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(ConnectorCapability::{ Json | - GeoJsonGeometry | + Geometry | Enums | EnumArrayPush | RelationFieldsInArbitraryOrder | diff --git a/psl/psl-core/src/builtin_connectors/mongodb/mongodb_types.rs b/psl/psl-core/src/builtin_connectors/mongodb/mongodb_types.rs index 6de813439984..102c0dc97e7d 100644 --- a/psl/psl-core/src/builtin_connectors/mongodb/mongodb_types.rs +++ b/psl/psl-core/src/builtin_connectors/mongodb/mongodb_types.rs @@ -16,7 +16,7 @@ crate::native_type_definition! { Int -> Int, Timestamp -> DateTime, Long -> Int | BigInt, - Json -> Json | GeoJson, + Json -> Json | Geometry, // Deprecated: // DbPointer // Undefined @@ -42,7 +42,7 @@ static DEFAULT_MAPPING: Lazy> = Lazy::new(|| { (ScalarType::DateTime, MongoDbType::Date), (ScalarType::Bytes, MongoDbType::BinData), (ScalarType::Json, MongoDbType::Json), - (ScalarType::GeoJson, MongoDbType::Json), + (ScalarType::Geometry, MongoDbType::Json), ] .into_iter() .collect() diff --git a/psl/psl-core/src/builtin_connectors/mssql_datamodel_connector.rs b/psl/psl-core/src/builtin_connectors/mssql_datamodel_connector.rs index ee84bbe9fd30..b063ffbbf4f3 100644 --- a/psl/psl-core/src/builtin_connectors/mssql_datamodel_connector.rs +++ b/psl/psl-core/src/builtin_connectors/mssql_datamodel_connector.rs @@ -26,8 +26,7 @@ const CONSTRAINT_SCOPES: &[ConstraintScope] = &[ ]; const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(ConnectorCapability::{ - EwktGeometry | - GeoJsonGeometry | + Geometry | GeometryFiltering | AnyId | AutoIncrement | @@ -78,7 +77,6 @@ const SCALAR_TYPE_DEFAULTS: &[(ScalarType, MsSqlType)] = &[ MsSqlType::NVarChar(Some(MsSqlTypeParameter::Number(1000))), ), (ScalarType::Geometry, MsSqlType::Geometry), - (ScalarType::GeoJson, MsSqlType::Geometry), ]; impl Connector for MsSqlDatamodelConnector { diff --git a/psl/psl-core/src/builtin_connectors/mssql_datamodel_connector/native_types.rs b/psl/psl-core/src/builtin_connectors/mssql_datamodel_connector/native_types.rs index 3c11d0722f2f..605bff16c7b9 100644 --- a/psl/psl-core/src/builtin_connectors/mssql_datamodel_connector/native_types.rs +++ b/psl/psl-core/src/builtin_connectors/mssql_datamodel_connector/native_types.rs @@ -104,6 +104,6 @@ crate::native_type_definition! { /// GUID, which is UUID but Microsoft invented them so they have their own /// term for it. UniqueIdentifier -> String, - Geometry -> Geometry | GeoJson, - Geography -> Geometry | GeoJson, + Geometry -> Geometry, + Geography -> Geometry, } diff --git a/psl/psl-core/src/builtin_connectors/mysql_datamodel_connector.rs b/psl/psl-core/src/builtin_connectors/mysql_datamodel_connector.rs index d5b6e8d6b2e9..a400132ea403 100644 --- a/psl/psl-core/src/builtin_connectors/mysql_datamodel_connector.rs +++ b/psl/psl-core/src/builtin_connectors/mysql_datamodel_connector.rs @@ -37,10 +37,10 @@ pub const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(Conne Enums | EnumArrayPush | Json | - EwktGeometry | - GeoJsonGeometry | + Geometry | GeometryRawRead | GeometryFiltering | + GeometryGeoJsonIO | AutoIncrementAllowedOnNonId | RelationFieldsInArbitraryOrder | CreateMany | @@ -91,7 +91,6 @@ const SCALAR_TYPE_DEFAULTS: &[(ScalarType, MySqlType)] = &[ (ScalarType::Bytes, MySqlType::LongBlob), (ScalarType::Json, MySqlType::Json), (ScalarType::Geometry, MySqlType::Geometry(None)), - (ScalarType::GeoJson, MySqlType::Geometry(None)), ]; impl Connector for MySqlDatamodelConnector { @@ -232,18 +231,6 @@ impl Connector for MySqlDatamodelConnector { VarChar(length) if *length > 65535 => { errors.push_error(error.new_argument_m_out_of_range_error("M can range from 0 to 65,535.", span)) } - Geometry(Some(srid)) - | Point(Some(srid)) - | LineString(Some(srid)) - | Polygon(Some(srid)) - | MultiPoint(Some(srid)) - | MultiLineString(Some(srid)) - | MultiPolygon(Some(srid)) - | GeometryCollection(Some(srid)) - if *scalar_type == ScalarType::GeoJson && !matches!(*srid, 0 | 4326) => - { - errors.push_error(error.new_argument_m_out_of_range_error("GeoJson SRID must be 4326.", span)) - } Bit(n) if *n > 1 && matches!(scalar_type, ScalarType::Boolean) => { errors.push_error(error.new_argument_m_out_of_range_error("only Bit(1) can be used as Boolean.", span)) } diff --git a/psl/psl-core/src/builtin_connectors/mysql_datamodel_connector/native_types.rs b/psl/psl-core/src/builtin_connectors/mysql_datamodel_connector/native_types.rs index 0226658e5568..0793c57ca20b 100644 --- a/psl/psl-core/src/builtin_connectors/mysql_datamodel_connector/native_types.rs +++ b/psl/psl-core/src/builtin_connectors/mysql_datamodel_connector/native_types.rs @@ -33,14 +33,14 @@ crate::native_type_definition! { Timestamp(Option) -> DateTime, Year -> Int, Json -> Json, - Geometry(Option) -> Geometry | GeoJson, - Point(Option) -> Geometry | GeoJson, - LineString(Option) -> Geometry | GeoJson, - Polygon(Option) -> Geometry | GeoJson, - MultiPoint(Option) -> Geometry | GeoJson, - MultiLineString(Option) -> Geometry | GeoJson, - MultiPolygon(Option) -> Geometry | GeoJson, - GeometryCollection(Option) -> Geometry | GeoJson, + Geometry(Option) -> Geometry, + Point(Option) -> Geometry, + LineString(Option) -> Geometry, + Polygon(Option) -> Geometry, + MultiPoint(Option) -> Geometry, + MultiLineString(Option) -> Geometry, + MultiPolygon(Option) -> Geometry, + GeometryCollection(Option) -> Geometry, } impl MySqlType { diff --git a/psl/psl-core/src/builtin_connectors/postgres_datamodel_connector.rs b/psl/psl-core/src/builtin_connectors/postgres_datamodel_connector.rs index 6f37d3dd76a1..d64b29cef8c5 100644 --- a/psl/psl-core/src/builtin_connectors/postgres_datamodel_connector.rs +++ b/psl/psl-core/src/builtin_connectors/postgres_datamodel_connector.rs @@ -50,9 +50,9 @@ pub const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(Conne JsonFilteringArrayPath | JsonFilteringAlphanumeric | JsonFilteringAlphanumericFieldRef | - EwktGeometry | - GeoJsonGeometry | + Geometry | GeometryRawRead | + GeometryGeoJsonIO | GeometryFiltering | GeometryExtraDims | GeometryExtraTypes | @@ -103,13 +103,6 @@ const SCALAR_TYPE_DEFAULTS: &[(ScalarType, PostgresType)] = &[ srid: 0, })), ), - ( - ScalarType::GeoJson, - PostgresType::Geometry(Some(GeometryParams { - type_: GeometryType::Geometry, - srid: 0, - })), - ), ]; /// Postgres-specific properties in the datasource block. @@ -385,7 +378,7 @@ impl Connector for PostgresDatamodelConnector { fn validate_native_type_arguments( &self, native_type_instance: &NativeTypeInstance, - scalar_type: &ScalarType, + _scalar_type: &ScalarType, span: ast::Span, errors: &mut Diagnostics, ) { @@ -408,21 +401,6 @@ impl Connector for PostgresDatamodelConnector { Timestamp(Some(p)) | Timestamptz(Some(p)) | Time(Some(p)) | Timetz(Some(p)) if *p > 6 => { errors.push_error(error.new_argument_m_out_of_range_error("M can range from 0 to 6.", span)) } - Geometry(Some(g)) | Geography(Some(g)) - if *scalar_type == ScalarType::GeoJson && !g.type_.is_geojson_compatible() => - { - errors.push_error( - error.new_argument_m_out_of_range_error( - &format!("{} isn't compatible with GeoJson.", g.type_), - span, - ), - ) - } - Geometry(Some(g)) | Geography(Some(g)) - if *scalar_type == ScalarType::GeoJson && !matches!(g.srid, 0 | 4326) => - { - errors.push_error(error.new_argument_m_out_of_range_error("GeoJson SRID must be 4326.", span)) - } Geometry(Some(g)) | Geography(Some(g)) if g.srid < 0 || g.srid > 999000 => { errors.push_error(error.new_argument_m_out_of_range_error("SRID must be between 0 and 999000.", span)) } diff --git a/psl/psl-core/src/builtin_connectors/postgres_datamodel_connector/native_types.rs b/psl/psl-core/src/builtin_connectors/postgres_datamodel_connector/native_types.rs index f3c239acf2bd..2b2e8738fe80 100644 --- a/psl/psl-core/src/builtin_connectors/postgres_datamodel_connector/native_types.rs +++ b/psl/psl-core/src/builtin_connectors/postgres_datamodel_connector/native_types.rs @@ -28,6 +28,6 @@ crate::native_type_definition! { Xml -> String, Json -> Json, JsonB -> Json, - Geometry(Option) -> Geometry | GeoJson, - Geography(Option) -> Geometry | GeoJson, + Geometry(Option) -> Geometry, + Geography(Option) -> Geometry, } diff --git a/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs b/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs index e9450f50fb69..e5043bc4e204 100644 --- a/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs +++ b/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs @@ -18,9 +18,9 @@ pub const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(Conne AnyId | AutoIncrement | CompoundIds | - EwktGeometry | - GeoJsonGeometry | + Geometry | GeometryRawRead | + GeometryGeoJsonIO | GeometryFiltering | GeometryExtraDims | SqlQueryRaw | @@ -42,22 +42,13 @@ pub const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(Conne CreateManyWriteableAutoIncId }); -const SCALAR_TYPE_DEFAULTS: &[(ScalarType, SQLiteType)] = &[ - ( - ScalarType::Geometry, - SQLiteType::Geometry(Some(GeometryParams { - type_: GeometryType::Geometry, - srid: 0, - })), - ), - ( - ScalarType::GeoJson, - SQLiteType::Geometry(Some(GeometryParams { - type_: GeometryType::Geometry, - srid: 0, - })), - ), -]; +const SCALAR_TYPE_DEFAULTS: &[(ScalarType, SQLiteType)] = &[( + ScalarType::Geometry, + SQLiteType::Geometry(Some(GeometryParams { + type_: GeometryType::Geometry, + srid: 0, + })), +)]; pub struct SqliteDatamodelConnector; @@ -121,7 +112,7 @@ impl Connector for SqliteDatamodelConnector { fn validate_native_type_arguments( &self, native_type_instance: &NativeTypeInstance, - scalar_type: &ScalarType, + _scalar_type: &ScalarType, span: Span, errors: &mut Diagnostics, ) { @@ -129,19 +120,6 @@ impl Connector for SqliteDatamodelConnector { let error = self.native_instance_error(native_type_instance); match native_type { - SQLiteType::Geometry(Some(g)) - if *scalar_type == ScalarType::GeoJson && !g.type_.is_geojson_compatible() => - { - errors.push_error( - error.new_argument_m_out_of_range_error( - &format!("{} isn't compatible with GeoJson.", g.type_), - span, - ), - ) - } - SQLiteType::Geometry(Some(g)) if *scalar_type == ScalarType::GeoJson && !matches!(g.srid, 0 | 4326) => { - errors.push_error(error.new_argument_m_out_of_range_error("GeoJson SRID must be 4326.", span)) - } SQLiteType::Geometry(Some(g)) if g.srid < -1 => errors .push_error(error.new_argument_m_out_of_range_error("SRID must be superior or equal to -1.", span)), _ => (), diff --git a/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector/native_types.rs b/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector/native_types.rs index 55a8dabdf25b..ec5aa57edbd5 100644 --- a/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector/native_types.rs +++ b/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector/native_types.rs @@ -3,5 +3,5 @@ use crate::builtin_connectors::geometry::GeometryParams; crate::native_type_definition! { /// The SQLite native type enum. SQLiteType; - Geometry(Option) -> Geometry | GeoJson, + Geometry(Option) -> Geometry, } diff --git a/psl/psl-core/src/datamodel_connector.rs b/psl/psl-core/src/datamodel_connector.rs index 28411c0589c0..64a95fd3c4d0 100644 --- a/psl/psl-core/src/datamodel_connector.rs +++ b/psl/psl-core/src/datamodel_connector.rs @@ -223,12 +223,8 @@ pub trait Connector: Send + Sync { } } - fn supports_ewkt_geometry_format(&self) -> bool { - self.capabilities().contains(ConnectorCapability::EwktGeometry) - } - - fn supports_geojson_geometry_format(&self) -> bool { - self.capabilities().contains(ConnectorCapability::GeoJsonGeometry) + fn supports_geometry_type(&self) -> bool { + self.capabilities().contains(ConnectorCapability::Geometry) } fn supports_raw_geometry_read(&self) -> bool { diff --git a/psl/psl-core/src/datamodel_connector/capabilities.rs b/psl/psl-core/src/datamodel_connector/capabilities.rs index a81b6d4f47e6..e55839c74339 100644 --- a/psl/psl-core/src/datamodel_connector/capabilities.rs +++ b/psl/psl-core/src/datamodel_connector/capabilities.rs @@ -55,8 +55,8 @@ capabilities!( TwoWayEmbeddedManyToManyRelation, ImplicitManyToManyRelation, MultiSchema, - EwktGeometry, - GeoJsonGeometry, + Geometry, + GeometryGeoJsonIO, GeometryRawRead, GeometryFiltering, GeometryExtraDims, diff --git a/psl/psl-core/src/datamodel_connector/empty_connector.rs b/psl/psl-core/src/datamodel_connector/empty_connector.rs index c3b987878f59..efd0517485a4 100644 --- a/psl/psl-core/src/datamodel_connector/empty_connector.rs +++ b/psl/psl-core/src/datamodel_connector/empty_connector.rs @@ -25,7 +25,7 @@ impl Connector for EmptyDatamodelConnector { CompoundIds | Enums | Json | - GeoJsonGeometry | + Geometry | ImplicitManyToManyRelation }) } diff --git a/psl/psl-core/src/validate/validation_pipeline/validations/fields.rs b/psl/psl-core/src/validate/validation_pipeline/validations/fields.rs index 4d558e2375f1..2ec5b6493e10 100644 --- a/psl/psl-core/src/validate/validation_pipeline/validations/fields.rs +++ b/psl/psl-core/src/validate/validation_pipeline/validations/fields.rs @@ -299,7 +299,7 @@ pub(super) fn validate_scalar_field_connector_specific(field: ScalarFieldWalker< } ScalarFieldType::BuiltInScalar(ScalarType::Geometry) => { - if !ctx.connector.supports_ewkt_geometry_format() { + if !ctx.connector.supports_geometry_type() { ctx.push_error(DatamodelError::new_field_validation_error( &format!( "Field `{}` in {container} `{}` can't be of type Geometry. The current connector does not support the Geometry type.", @@ -314,22 +314,6 @@ pub(super) fn validate_scalar_field_connector_specific(field: ScalarFieldWalker< } } - ScalarFieldType::BuiltInScalar(ScalarType::GeoJson) => { - if !ctx.connector.supports_geojson_geometry_format() { - ctx.push_error(DatamodelError::new_field_validation_error( - &format!( - "Field `{}` in {container} `{}` can't be of type GeoJson. The current connector does not support the GeoJson type.", - field.name(), - field.model().name(), - ), - container, - field.model().name(), - field.name(), - field.ast_field().span(), - )); - } - } - _ => (), } diff --git a/psl/psl/tests/base/base_types.rs b/psl/psl/tests/base/base_types.rs index aacd4dae4198..b69329fe7312 100644 --- a/psl/psl/tests/base/base_types.rs +++ b/psl/psl/tests/base/base_types.rs @@ -10,7 +10,7 @@ fn parse_scalar_types() { age Int isPro Boolean averageGrade Float - location GeoJson + location Geometry } "#; @@ -35,7 +35,7 @@ fn parse_scalar_types() { user_model .assert_has_scalar_field("location") - .assert_scalar_type(ScalarType::GeoJson); + .assert_scalar_type(ScalarType::Geometry); } #[test] diff --git a/psl/psl/tests/types/cockroachdb_native_types.rs b/psl/psl/tests/types/cockroachdb_native_types.rs index 10d9fbad336e..609e38d7296d 100644 --- a/psl/psl/tests/types/cockroachdb_native_types.rs +++ b/psl/psl/tests/types/cockroachdb_native_types.rs @@ -186,76 +186,40 @@ fn cockroach_specific_native_types_are_valid() { varbitcol String @db.VarBit(200) geomcol1 Geometry @db.Geometry(Geometry, 4326) geomcol2 Geometry @db.Geometry(GeometryZ, 4326) - geomcol3 Geometry @db.Geometry(GeometryM, 4326) - geomcol4 Geometry @db.Geometry(GeometryZM, 4326) + geomcol3 Geometry @db.Geometry(Point, 4326) + geomcol4 Geometry @db.Geometry(PointZ, 4326) geomcol5 Geometry @db.Geometry(Point, 4326) - geomcol6 Geometry @db.Geometry(PointZ, 4326) - geomcol7 Geometry @db.Geometry(PointM, 4326) - geomcol8 Geometry @db.Geometry(PointZM, 4326) - geomcol9 Geometry @db.Geometry(Point, 4326) - geomcol10 Geometry @db.Geometry(PointZ, 4326) - geomcol11 Geometry @db.Geometry(PointM, 4326) - geomcol12 Geometry @db.Geometry(PointZM, 4326) - geomcol13 Geometry @db.Geometry(LineString, 4326) - geomcol14 Geometry @db.Geometry(LineStringZ, 4326) - geomcol15 Geometry @db.Geometry(LineStringM, 4326) - geomcol16 Geometry @db.Geometry(LineStringZM, 4326) - geomcol17 Geometry @db.Geometry(Polygon, 4326) - geomcol18 Geometry @db.Geometry(PolygonZ, 4326) - geomcol19 Geometry @db.Geometry(PolygonM, 4326) - geomcol20 Geometry @db.Geometry(PolygonZM, 4326) - geomcol21 Geometry @db.Geometry(MultiPoint, 4326) - geomcol22 Geometry @db.Geometry(MultiPointZ, 4326) - geomcol23 Geometry @db.Geometry(MultiPointM, 4326) - geomcol24 Geometry @db.Geometry(MultiPointZM, 4326) - geomcol25 Geometry @db.Geometry(MultiLineString, 4326) - geomcol26 Geometry @db.Geometry(MultiLineStringZ, 4326) - geomcol27 Geometry @db.Geometry(MultiLineStringM, 4326) - geomcol28 Geometry @db.Geometry(MultiLineStringZM, 4326) - geomcol29 Geometry @db.Geometry(MultiPolygon, 4326) - geomcol30 Geometry @db.Geometry(MultiPolygonZ, 4326) - geomcol31 Geometry @db.Geometry(MultiPolygonM, 4326) - geomcol32 Geometry @db.Geometry(MultiPolygonZM, 4326) - geomcol33 Geometry @db.Geometry(GeometryCollection, 4326) - geomcol34 Geometry @db.Geometry(GeometryCollectionZ, 4326) - geomcol35 Geometry @db.Geometry(GeometryCollectionM, 4326) - geomcol36 Geometry @db.Geometry(GeometryCollectionZM, 4326) + geomcol6 Geometry @db.Geometry(PointZ, 4326) + geomcol7 Geometry @db.Geometry(LineString, 4326) + geomcol8 Geometry @db.Geometry(LineStringZ, 4326) + geomcol9 Geometry @db.Geometry(Polygon, 4326) + geomcol10 Geometry @db.Geometry(PolygonZ, 4326) + geomcol11 Geometry @db.Geometry(MultiPoint, 4326) + geomcol12 Geometry @db.Geometry(MultiPointZ, 4326) + geomcol13 Geometry @db.Geometry(MultiLineString, 4326) + geomcol14 Geometry @db.Geometry(MultiLineStringZ, 4326) + geomcol15 Geometry @db.Geometry(MultiPolygon, 4326) + geomcol16 Geometry @db.Geometry(MultiPolygonZ, 4326) + geomcol17 Geometry @db.Geometry(GeometryCollection, 4326) + geomcol18 Geometry @db.Geometry(GeometryCollectionZ, 4326) geogcol1 Geometry @db.Geography(Geometry, 4326) geogcol2 Geometry @db.Geography(GeometryZ, 4326) - geogcol3 Geometry @db.Geography(GeometryM, 4326) - geogcol4 Geometry @db.Geography(GeometryZM, 4326) + geogcol3 Geometry @db.Geography(Point, 4326) + geogcol4 Geometry @db.Geography(PointZ, 4326) geogcol5 Geometry @db.Geography(Point, 4326) - geogcol6 Geometry @db.Geography(PointZ, 4326) - geogcol7 Geometry @db.Geography(PointM, 4326) - geogcol8 Geometry @db.Geography(PointZM, 4326) - geogcol9 Geometry @db.Geography(Point, 4326) - geogcol10 Geometry @db.Geography(PointZ, 4326) - geogcol11 Geometry @db.Geography(PointM, 4326) - geogcol12 Geometry @db.Geography(PointZM, 4326) - geogcol13 Geometry @db.Geography(LineString, 4326) - geogcol14 Geometry @db.Geography(LineStringZ, 4326) - geogcol15 Geometry @db.Geography(LineStringM, 4326) - geogcol16 Geometry @db.Geography(LineStringZM, 4326) - geogcol17 Geometry @db.Geography(Polygon, 4326) - geogcol18 Geometry @db.Geography(PolygonZ, 4326) - geogcol19 Geometry @db.Geography(PolygonM, 4326) - geogcol20 Geometry @db.Geography(PolygonZM, 4326) - geogcol21 Geometry @db.Geography(MultiPoint, 4326) - geogcol22 Geometry @db.Geography(MultiPointZ, 4326) - geogcol23 Geometry @db.Geography(MultiPointM, 4326) - geogcol24 Geometry @db.Geography(MultiPointZM, 4326) - geogcol25 Geometry @db.Geography(MultiLineString, 4326) - geogcol26 Geometry @db.Geography(MultiLineStringZ, 4326) - geogcol27 Geometry @db.Geography(MultiLineStringM, 4326) - geogcol28 Geometry @db.Geography(MultiLineStringZM, 4326) - geogcol29 Geometry @db.Geography(MultiPolygon, 4326) - geogcol30 Geometry @db.Geography(MultiPolygonZ, 4326) - geogcol31 Geometry @db.Geography(MultiPolygonM, 4326) - geogcol32 Geometry @db.Geography(MultiPolygonZM, 4326) - geogcol33 Geometry @db.Geography(GeometryCollection, 4326) - geogcol34 Geometry @db.Geography(GeometryCollectionZ, 4326) - geogcol35 Geometry @db.Geography(GeometryCollectionM, 4326) - geogcol36 Geometry @db.Geography(GeometryCollectionZM, 4326) + geogcol6 Geometry @db.Geography(PointZ, 4326) + geogcol7 Geometry @db.Geography(LineString, 4326) + geogcol8 Geometry @db.Geography(LineStringZ, 4326) + geogcol9 Geometry @db.Geography(Polygon, 4326) + geogcol10 Geometry @db.Geography(PolygonZ, 4326) + geogcol11 Geometry @db.Geography(MultiPoint, 4326) + geogcol12 Geometry @db.Geography(MultiPointZ, 4326) + geogcol13 Geometry @db.Geography(MultiLineString, 4326) + geogcol14 Geometry @db.Geography(MultiLineStringZ, 4326) + geogcol15 Geometry @db.Geography(MultiPolygon, 4326) + geogcol16 Geometry @db.Geography(MultiPolygonZ, 4326) + geogcol17 Geometry @db.Geography(GeometryCollection, 4326) + geogcol18 Geometry @db.Geography(GeometryCollectionZ, 4326) } "#}; @@ -263,7 +227,7 @@ fn cockroach_specific_native_types_are_valid() { } #[test] -fn should_fail_on_geojson_when_incompatible_geometry_type() { +fn should_fail_on_geometry_when_invalid_geometry_type() { let dml = indoc! {r#" datasource db { provider = "cockroachdb" @@ -271,279 +235,8 @@ fn should_fail_on_geojson_when_incompatible_geometry_type() { } model Blog { - id Int @id - geomcol1 GeoJson @db.Geometry(GeometryM, 4326) - geomcol2 GeoJson @db.Geometry(GeometryZM, 4326) - geomcol3 GeoJson @db.Geometry(PointM, 4326) - geomcol4 GeoJson @db.Geometry(PointZM, 4326) - geomcol5 GeoJson @db.Geometry(PointM, 4326) - geomcol6 GeoJson @db.Geometry(PointZM, 4326) - geomcol7 GeoJson @db.Geometry(LineStringM, 4326) - geomcol8 GeoJson @db.Geometry(LineStringZM, 4326) - geomcol9 GeoJson @db.Geometry(PolygonM, 4326) - geomcol10 GeoJson @db.Geometry(PolygonZM, 4326) - geomcol11 GeoJson @db.Geometry(MultiPointM, 4326) - geomcol12 GeoJson @db.Geometry(MultiPointZM, 4326) - geomcol13 GeoJson @db.Geometry(MultiLineStringM, 4326) - geomcol14 GeoJson @db.Geometry(MultiLineStringZM, 4326) - geomcol15 GeoJson @db.Geometry(MultiPolygonM, 4326) - geomcol16 GeoJson @db.Geometry(MultiPolygonZM, 4326) - geomcol17 GeoJson @db.Geometry(GeometryCollectionM, 4326) - geomcol18 GeoJson @db.Geometry(GeometryCollectionZM, 4326) - geogcol1 GeoJson @db.Geography(GeometryM, 4326) - geogcol2 GeoJson @db.Geography(GeometryZM, 4326) - geogcol3 GeoJson @db.Geography(PointM, 4326) - geogcol4 GeoJson @db.Geography(PointZM, 4326) - geogcol5 GeoJson @db.Geography(PointM, 4326) - geogcol6 GeoJson @db.Geography(PointZM, 4326) - geogcol7 GeoJson @db.Geography(LineStringM, 4326) - geogcol8 GeoJson @db.Geography(LineStringZM, 4326) - geogcol9 GeoJson @db.Geography(PolygonM, 4326) - geogcol10 GeoJson @db.Geography(PolygonZM, 4326) - geogcol11 GeoJson @db.Geography(MultiPointM, 4326) - geogcol12 GeoJson @db.Geography(MultiPointZM, 4326) - geogcol13 GeoJson @db.Geography(MultiLineStringM, 4326) - geogcol14 GeoJson @db.Geography(MultiLineStringZM, 4326) - geogcol15 GeoJson @db.Geography(MultiPolygonM, 4326) - geogcol16 GeoJson @db.Geography(MultiPolygonZM, 4326) - geogcol17 GeoJson @db.Geography(GeometryCollectionM, 4326) - geogcol18 GeoJson @db.Geography(GeometryCollectionZM, 4326) - } - "#}; - - let expectation = expect![[r#" - error: Argument M is out of range for native type `Geometry(GeometryM,4326)` of CockroachDB: GeometryM isn't compatible with GeoJson. - --> schema.prisma:8 -  |  -  7 |  id Int @id -  8 |  geomcol1 GeoJson @db.Geometry(GeometryM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(GeometryZM,4326)` of CockroachDB: GeometryZM isn't compatible with GeoJson. - --> schema.prisma:9 -  |  -  8 |  geomcol1 GeoJson @db.Geometry(GeometryM, 4326) -  9 |  geomcol2 GeoJson @db.Geometry(GeometryZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(PointM,4326)` of CockroachDB: PointM isn't compatible with GeoJson. - --> schema.prisma:10 -  |  -  9 |  geomcol2 GeoJson @db.Geometry(GeometryZM, 4326) - 10 |  geomcol3 GeoJson @db.Geometry(PointM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(PointZM,4326)` of CockroachDB: PointZM isn't compatible with GeoJson. - --> schema.prisma:11 -  |  - 10 |  geomcol3 GeoJson @db.Geometry(PointM, 4326) - 11 |  geomcol4 GeoJson @db.Geometry(PointZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(PointM,4326)` of CockroachDB: PointM isn't compatible with GeoJson. - --> schema.prisma:12 -  |  - 11 |  geomcol4 GeoJson @db.Geometry(PointZM, 4326) - 12 |  geomcol5 GeoJson @db.Geometry(PointM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(PointZM,4326)` of CockroachDB: PointZM isn't compatible with GeoJson. - --> schema.prisma:13 -  |  - 12 |  geomcol5 GeoJson @db.Geometry(PointM, 4326) - 13 |  geomcol6 GeoJson @db.Geometry(PointZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(LineStringM,4326)` of CockroachDB: LineStringM isn't compatible with GeoJson. - --> schema.prisma:14 -  |  - 13 |  geomcol6 GeoJson @db.Geometry(PointZM, 4326) - 14 |  geomcol7 GeoJson @db.Geometry(LineStringM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(LineStringZM,4326)` of CockroachDB: LineStringZM isn't compatible with GeoJson. - --> schema.prisma:15 -  |  - 14 |  geomcol7 GeoJson @db.Geometry(LineStringM, 4326) - 15 |  geomcol8 GeoJson @db.Geometry(LineStringZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(PolygonM,4326)` of CockroachDB: PolygonM isn't compatible with GeoJson. - --> schema.prisma:16 -  |  - 15 |  geomcol8 GeoJson @db.Geometry(LineStringZM, 4326) - 16 |  geomcol9 GeoJson @db.Geometry(PolygonM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(PolygonZM,4326)` of CockroachDB: PolygonZM isn't compatible with GeoJson. - --> schema.prisma:17 -  |  - 16 |  geomcol9 GeoJson @db.Geometry(PolygonM, 4326) - 17 |  geomcol10 GeoJson @db.Geometry(PolygonZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiPointM,4326)` of CockroachDB: MultiPointM isn't compatible with GeoJson. - --> schema.prisma:18 -  |  - 17 |  geomcol10 GeoJson @db.Geometry(PolygonZM, 4326) - 18 |  geomcol11 GeoJson @db.Geometry(MultiPointM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiPointZM,4326)` of CockroachDB: MultiPointZM isn't compatible with GeoJson. - --> schema.prisma:19 -  |  - 18 |  geomcol11 GeoJson @db.Geometry(MultiPointM, 4326) - 19 |  geomcol12 GeoJson @db.Geometry(MultiPointZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiLineStringM,4326)` of CockroachDB: MultiLineStringM isn't compatible with GeoJson. - --> schema.prisma:20 -  |  - 19 |  geomcol12 GeoJson @db.Geometry(MultiPointZM, 4326) - 20 |  geomcol13 GeoJson @db.Geometry(MultiLineStringM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiLineStringZM,4326)` of CockroachDB: MultiLineStringZM isn't compatible with GeoJson. - --> schema.prisma:21 -  |  - 20 |  geomcol13 GeoJson @db.Geometry(MultiLineStringM, 4326) - 21 |  geomcol14 GeoJson @db.Geometry(MultiLineStringZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiPolygonM,4326)` of CockroachDB: MultiPolygonM isn't compatible with GeoJson. - --> schema.prisma:22 -  |  - 21 |  geomcol14 GeoJson @db.Geometry(MultiLineStringZM, 4326) - 22 |  geomcol15 GeoJson @db.Geometry(MultiPolygonM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiPolygonZM,4326)` of CockroachDB: MultiPolygonZM isn't compatible with GeoJson. - --> schema.prisma:23 -  |  - 22 |  geomcol15 GeoJson @db.Geometry(MultiPolygonM, 4326) - 23 |  geomcol16 GeoJson @db.Geometry(MultiPolygonZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(GeometryCollectionM,4326)` of CockroachDB: GeometryCollectionM isn't compatible with GeoJson. - --> schema.prisma:24 -  |  - 23 |  geomcol16 GeoJson @db.Geometry(MultiPolygonZM, 4326) - 24 |  geomcol17 GeoJson @db.Geometry(GeometryCollectionM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(GeometryCollectionZM,4326)` of CockroachDB: GeometryCollectionZM isn't compatible with GeoJson. - --> schema.prisma:25 -  |  - 24 |  geomcol17 GeoJson @db.Geometry(GeometryCollectionM, 4326) - 25 |  geomcol18 GeoJson @db.Geometry(GeometryCollectionZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(GeometryM,4326)` of CockroachDB: GeometryM isn't compatible with GeoJson. - --> schema.prisma:26 -  |  - 25 |  geomcol18 GeoJson @db.Geometry(GeometryCollectionZM, 4326) - 26 |  geogcol1 GeoJson @db.Geography(GeometryM, 4326) -  |  - error: Argument M is out of range for native type `Geography(GeometryZM,4326)` of CockroachDB: GeometryZM isn't compatible with GeoJson. - --> schema.prisma:27 -  |  - 26 |  geogcol1 GeoJson @db.Geography(GeometryM, 4326) - 27 |  geogcol2 GeoJson @db.Geography(GeometryZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(PointM,4326)` of CockroachDB: PointM isn't compatible with GeoJson. - --> schema.prisma:28 -  |  - 27 |  geogcol2 GeoJson @db.Geography(GeometryZM, 4326) - 28 |  geogcol3 GeoJson @db.Geography(PointM, 4326) -  |  - error: Argument M is out of range for native type `Geography(PointZM,4326)` of CockroachDB: PointZM isn't compatible with GeoJson. - --> schema.prisma:29 -  |  - 28 |  geogcol3 GeoJson @db.Geography(PointM, 4326) - 29 |  geogcol4 GeoJson @db.Geography(PointZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(PointM,4326)` of CockroachDB: PointM isn't compatible with GeoJson. - --> schema.prisma:30 -  |  - 29 |  geogcol4 GeoJson @db.Geography(PointZM, 4326) - 30 |  geogcol5 GeoJson @db.Geography(PointM, 4326) -  |  - error: Argument M is out of range for native type `Geography(PointZM,4326)` of CockroachDB: PointZM isn't compatible with GeoJson. - --> schema.prisma:31 -  |  - 30 |  geogcol5 GeoJson @db.Geography(PointM, 4326) - 31 |  geogcol6 GeoJson @db.Geography(PointZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(LineStringM,4326)` of CockroachDB: LineStringM isn't compatible with GeoJson. - --> schema.prisma:32 -  |  - 31 |  geogcol6 GeoJson @db.Geography(PointZM, 4326) - 32 |  geogcol7 GeoJson @db.Geography(LineStringM, 4326) -  |  - error: Argument M is out of range for native type `Geography(LineStringZM,4326)` of CockroachDB: LineStringZM isn't compatible with GeoJson. - --> schema.prisma:33 -  |  - 32 |  geogcol7 GeoJson @db.Geography(LineStringM, 4326) - 33 |  geogcol8 GeoJson @db.Geography(LineStringZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(PolygonM,4326)` of CockroachDB: PolygonM isn't compatible with GeoJson. - --> schema.prisma:34 -  |  - 33 |  geogcol8 GeoJson @db.Geography(LineStringZM, 4326) - 34 |  geogcol9 GeoJson @db.Geography(PolygonM, 4326) -  |  - error: Argument M is out of range for native type `Geography(PolygonZM,4326)` of CockroachDB: PolygonZM isn't compatible with GeoJson. - --> schema.prisma:35 -  |  - 34 |  geogcol9 GeoJson @db.Geography(PolygonM, 4326) - 35 |  geogcol10 GeoJson @db.Geography(PolygonZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiPointM,4326)` of CockroachDB: MultiPointM isn't compatible with GeoJson. - --> schema.prisma:36 -  |  - 35 |  geogcol10 GeoJson @db.Geography(PolygonZM, 4326) - 36 |  geogcol11 GeoJson @db.Geography(MultiPointM, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiPointZM,4326)` of CockroachDB: MultiPointZM isn't compatible with GeoJson. - --> schema.prisma:37 -  |  - 36 |  geogcol11 GeoJson @db.Geography(MultiPointM, 4326) - 37 |  geogcol12 GeoJson @db.Geography(MultiPointZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiLineStringM,4326)` of CockroachDB: MultiLineStringM isn't compatible with GeoJson. - --> schema.prisma:38 -  |  - 37 |  geogcol12 GeoJson @db.Geography(MultiPointZM, 4326) - 38 |  geogcol13 GeoJson @db.Geography(MultiLineStringM, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiLineStringZM,4326)` of CockroachDB: MultiLineStringZM isn't compatible with GeoJson. - --> schema.prisma:39 -  |  - 38 |  geogcol13 GeoJson @db.Geography(MultiLineStringM, 4326) - 39 |  geogcol14 GeoJson @db.Geography(MultiLineStringZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiPolygonM,4326)` of CockroachDB: MultiPolygonM isn't compatible with GeoJson. - --> schema.prisma:40 -  |  - 39 |  geogcol14 GeoJson @db.Geography(MultiLineStringZM, 4326) - 40 |  geogcol15 GeoJson @db.Geography(MultiPolygonM, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiPolygonZM,4326)` of CockroachDB: MultiPolygonZM isn't compatible with GeoJson. - --> schema.prisma:41 -  |  - 40 |  geogcol15 GeoJson @db.Geography(MultiPolygonM, 4326) - 41 |  geogcol16 GeoJson @db.Geography(MultiPolygonZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(GeometryCollectionM,4326)` of CockroachDB: GeometryCollectionM isn't compatible with GeoJson. - --> schema.prisma:42 -  |  - 41 |  geogcol16 GeoJson @db.Geography(MultiPolygonZM, 4326) - 42 |  geogcol17 GeoJson @db.Geography(GeometryCollectionM, 4326) -  |  - error: Argument M is out of range for native type `Geography(GeometryCollectionZM,4326)` of CockroachDB: GeometryCollectionZM isn't compatible with GeoJson. - --> schema.prisma:43 -  |  - 42 |  geogcol17 GeoJson @db.Geography(GeometryCollectionM, 4326) - 43 |  geogcol18 GeoJson @db.Geography(GeometryCollectionZM, 4326) -  |  - "#]]; - - expect_error(dml, &expectation); -} - -#[test] -fn should_fail_on_geojson_when_invalid_geometry_type() { - let dml = indoc! {r#" - datasource db { - provider = "cockroachdb" - url = env("DATABASE_URL") - } - - model Blog { - id Int @id - geom GeoJson @db.Geometry(Invalid) + id Int @id + geom Geometry @db.Geometry(Invalid) } "#}; @@ -551,40 +244,14 @@ fn should_fail_on_geojson_when_invalid_geometry_type() { error: Expected a geometry type and an optional srid, but found (Invalid). --> schema.prisma:8  |  -  7 |  id Int @id -  8 |  geom GeoJson @db.Geometry(Invalid) +  7 |  id Int @id +  8 |  geom Geometry @db.Geometry(Invalid)  |  "#]]; expect_error(dml, &expectation); } -#[test] -fn should_fail_on_geojson_when_non_wgs84_srid() { - let schema = indoc! {r#" - datasource db { - provider = "cockroachdb" - url = env("DATABASE_URL") - } - - model User { - id Int @id - geom GeoJson @db.Geometry(Point, 3857) - } - "#}; - - let expectation = expect![[r#" - error: Argument M is out of range for native type `Geometry(Point,3857)` of CockroachDB: GeoJson SRID must be 4326. - --> schema.prisma:8 -  |  -  7 |  id Int @id -  8 |  geom GeoJson @db.Geometry(Point, 3857) -  |  - "#]]; - - expect_error(schema, &expectation); -} - #[test] fn should_fail_on_geometry_when_out_of_bound_srid() { let schema = indoc! {r#" diff --git a/psl/psl/tests/types/mssql_native_types.rs b/psl/psl/tests/types/mssql_native_types.rs index e85ede859506..06f7af9d7b30 100644 --- a/psl/psl/tests/types/mssql_native_types.rs +++ b/psl/psl/tests/types/mssql_native_types.rs @@ -213,11 +213,11 @@ fn geometry_type_should_fail_on_unique() { } model User { - id Int @id - geom GeoJson @db.Geometry - geog GeoJson @db.Geometry + id Int @id + a Geometry @db.Geometry + b Geometry @db.Geometry - @@unique([geom, geog]) + @@unique([a, b]) } "#}; @@ -226,7 +226,7 @@ fn geometry_type_should_fail_on_unique() { --> schema.prisma:11  |  10 |  - 11 |  @@unique([geom, geog]) + 11 |  @@unique([a, b])  |  "#]]; @@ -242,11 +242,11 @@ fn geography_type_should_fail_on_unique() { } model User { - id Int @id - geom GeoJson @db.Geography - geog GeoJson @db.Geography + id Int @id + a Geometry @db.Geography + b Geometry @db.Geography - @@unique([geom, geog]) + @@unique([a, b]) } "#}; @@ -255,7 +255,7 @@ fn geography_type_should_fail_on_unique() { --> schema.prisma:11  |  10 |  - 11 |  @@unique([geom, geog]) + 11 |  @@unique([a, b])  |  "#]]; @@ -474,11 +474,11 @@ fn geometry_type_should_fail_on_index() { } model User { - id Int @id - firstName GeoJson @db.Geometry - lastName GeoJson @db.Geometry + id Int @id + a Geometry @db.Geometry + b Geometry @db.Geometry - @@index([firstName, lastName]) + @@index([a, b]) } "#}; @@ -487,7 +487,7 @@ fn geometry_type_should_fail_on_index() { --> schema.prisma:11  |  10 |  - 11 |  @@index([firstName, lastName]) + 11 |  @@index([a, b])  |  "#]]; @@ -503,11 +503,11 @@ fn geography_type_should_fail_on_index() { } model User { - id Int @id - firstName GeoJson @db.Geography - lastName GeoJson @db.Geography + id Int @id + a Geometry @db.Geography + b Geometry @db.Geography - @@index([firstName, lastName]) + @@index([a, b]) } "#}; @@ -516,7 +516,7 @@ fn geography_type_should_fail_on_index() { --> schema.prisma:11  |  10 |  - 11 |  @@index([firstName, lastName]) + 11 |  @@index([a, b])  |  "#]]; @@ -728,10 +728,10 @@ fn geometry_type_should_fail_on_id() { } model User { - firstName GeoJson @db.Geometry - lastName GeoJson @db.Geometry + a Geometry @db.Geometry + b Geometry @db.Geometry - @@id([firstName, lastName]) + @@id([a, b]) } "#}; @@ -740,7 +740,7 @@ fn geometry_type_should_fail_on_id() { --> schema.prisma:10  |   9 |  - 10 |  @@id([firstName, lastName]) + 10 |  @@id([a, b])  |  "#]]; @@ -756,10 +756,10 @@ fn geography_type_should_fail_on_id() { } model User { - firstName GeoJson @db.Geography - lastName GeoJson @db.Geography + a Geometry @db.Geography + b Geometry @db.Geography - @@id([firstName, lastName]) + @@id([a, b]) } "#}; @@ -768,7 +768,7 @@ fn geography_type_should_fail_on_id() { --> schema.prisma:10  |   9 |  - 10 |  @@id([firstName, lastName]) + 10 |  @@id([a, b])  |  "#]]; @@ -1082,10 +1082,8 @@ mod test_type_mapping { test_type!(ntext(("String @db.NText", MsSqlType::NText))); test_type!(image(("Bytes @db.Image", MsSqlType::Image))); test_type!(xml(("String @db.Xml", MsSqlType::Xml))); - test_type!(geojsongeometry(("GeoJson @db.Geometry", MsSqlType::Geometry))); - test_type!(geojsongeography(("GeoJson @db.Geography", MsSqlType::Geography))); - test_type!(ewktgeometry(("Geometry @db.Geometry", MsSqlType::Geometry))); - test_type!(ewktgeography(("Geometry @db.Geography", MsSqlType::Geography))); + test_type!(geometry(("Geometry @db.Geometry", MsSqlType::Geometry))); + test_type!(geography(("Geometry @db.Geography", MsSqlType::Geography))); test_type!(datetimeoffset(( "DateTime @db.DateTimeOffset", diff --git a/psl/psl/tests/types/mysql_native_types.rs b/psl/psl/tests/types/mysql_native_types.rs index 2c15b4c7f499..4ba4ff91a04e 100644 --- a/psl/psl/tests/types/mysql_native_types.rs +++ b/psl/psl/tests/types/mysql_native_types.rs @@ -473,11 +473,11 @@ fn geometry_type_should_fail_on_index() { } model User { - id Int @id - firstName GeoJson @db.Geometry - lastName GeoJson @db.Geometry + id Int @id + a Geometry @db.Geometry + b Geometry @db.Geometry - @@index([firstName, lastName]) + @@index([a, b]) } "#}; @@ -486,7 +486,7 @@ fn geometry_type_should_fail_on_index() { --> schema.prisma:11  |  10 |  - 11 |  @@index([firstName, lastName]) + 11 |  @@index([a, b])  |  "#]]; @@ -502,11 +502,11 @@ fn point_type_should_fail_on_index() { } model User { - id Int @id - firstName GeoJson @db.Point - lastName GeoJson @db.Point + id Int @id + a Geometry @db.Point + b Geometry @db.Point - @@index([firstName, lastName]) + @@index([a, b]) } "#}; @@ -515,7 +515,7 @@ fn point_type_should_fail_on_index() { --> schema.prisma:11  |  10 |  - 11 |  @@index([firstName, lastName]) + 11 |  @@index([a, b])  |  "#]]; @@ -531,11 +531,11 @@ fn linestring_type_should_fail_on_index() { } model User { - id Int @id - firstName GeoJson @db.LineString - lastName GeoJson @db.LineString + id Int @id + a Geometry @db.LineString + b Geometry @db.LineString - @@index([firstName, lastName]) + @@index([a, b]) } "#}; @@ -544,7 +544,7 @@ fn linestring_type_should_fail_on_index() { --> schema.prisma:11  |  10 |  - 11 |  @@index([firstName, lastName]) + 11 |  @@index([a, b])  |  "#]]; @@ -560,11 +560,11 @@ fn polygon_type_should_fail_on_index() { } model User { - id Int @id - firstName GeoJson @db.Polygon - lastName GeoJson @db.Polygon + id Int @id + a Geometry @db.Polygon + b Geometry @db.Polygon - @@index([firstName, lastName]) + @@index([a, b]) } "#}; @@ -573,7 +573,7 @@ fn polygon_type_should_fail_on_index() { --> schema.prisma:11  |  10 |  - 11 |  @@index([firstName, lastName]) + 11 |  @@index([a, b])  |  "#]]; @@ -589,11 +589,11 @@ fn multipoint_type_should_fail_on_index() { } model User { - id Int @id - firstName GeoJson @db.MultiPoint - lastName GeoJson @db.MultiPoint + id Int @id + a Geometry @db.MultiPoint + b Geometry @db.MultiPoint - @@index([firstName, lastName]) + @@index([a, b]) } "#}; @@ -602,7 +602,7 @@ fn multipoint_type_should_fail_on_index() { --> schema.prisma:11  |  10 |  - 11 |  @@index([firstName, lastName]) + 11 |  @@index([a, b])  |  "#]]; @@ -618,11 +618,11 @@ fn multilinestring_type_should_fail_on_index() { } model User { - id Int @id - firstName GeoJson @db.MultiLineString - lastName GeoJson @db.MultiLineString + id Int @id + a Geometry @db.MultiLineString + b Geometry @db.MultiLineString - @@index([firstName, lastName]) + @@index([a, b]) } "#}; @@ -631,7 +631,7 @@ fn multilinestring_type_should_fail_on_index() { --> schema.prisma:11  |  10 |  - 11 |  @@index([firstName, lastName]) + 11 |  @@index([a, b])  |  "#]]; @@ -647,11 +647,11 @@ fn multipolygon_type_should_fail_on_index() { } model User { - id Int @id - firstName GeoJson @db.MultiPolygon - lastName GeoJson @db.MultiPolygon + id Int @id + a Geometry @db.MultiPolygon + b Geometry @db.MultiPolygon - @@index([firstName, lastName]) + @@index([a, b]) } "#}; @@ -660,7 +660,7 @@ fn multipolygon_type_should_fail_on_index() { --> schema.prisma:11  |  10 |  - 11 |  @@index([firstName, lastName]) + 11 |  @@index([a, b])  |  "#]]; @@ -676,11 +676,11 @@ fn geometrycollection_type_should_fail_on_index() { } model User { - id Int @id - firstName GeoJson @db.GeometryCollection - lastName GeoJson @db.GeometryCollection + id Int @id + a Geometry @db.GeometryCollection + b Geometry @db.GeometryCollection - @@index([firstName, lastName]) + @@index([a, b]) } "#}; @@ -689,7 +689,7 @@ fn geometrycollection_type_should_fail_on_index() { --> schema.prisma:11  |  10 |  - 11 |  @@index([firstName, lastName]) + 11 |  @@index([a, b])  |  "#]]; @@ -929,10 +929,10 @@ fn geometry_type_should_fail_on_id() { } model User { - firstName GeoJson @db.Geometry - lastName GeoJson @db.Geometry + a Geometry @db.Geometry + b Geometry @db.Geometry - @@id([firstName, lastName]) + @@id([a, b]) } "#}; @@ -941,7 +941,7 @@ fn geometry_type_should_fail_on_id() { --> schema.prisma:10  |   9 |  - 10 |  @@id([firstName, lastName]) + 10 |  @@id([a, b])  |  "#]]; @@ -957,10 +957,10 @@ fn point_type_should_fail_on_id() { } model User { - firstName GeoJson @db.Point - lastName GeoJson @db.Point + a Geometry @db.Point + b Geometry @db.Point - @@id([firstName, lastName]) + @@id([a, b]) } "#}; @@ -969,7 +969,7 @@ fn point_type_should_fail_on_id() { --> schema.prisma:10  |   9 |  - 10 |  @@id([firstName, lastName]) + 10 |  @@id([a, b])  |  "#]]; @@ -985,10 +985,10 @@ fn linestring_type_should_fail_on_id() { } model User { - firstName GeoJson @db.LineString - lastName GeoJson @db.LineString + a Geometry @db.LineString + b Geometry @db.LineString - @@id([firstName, lastName]) + @@id([a, b]) } "#}; @@ -997,7 +997,7 @@ fn linestring_type_should_fail_on_id() { --> schema.prisma:10  |   9 |  - 10 |  @@id([firstName, lastName]) + 10 |  @@id([a, b])  |  "#]]; @@ -1013,10 +1013,10 @@ fn polygon_type_should_fail_on_id() { } model User { - firstName GeoJson @db.Polygon - lastName GeoJson @db.Polygon + a Geometry @db.Polygon + b Geometry @db.Polygon - @@id([firstName, lastName]) + @@id([a, b]) } "#}; @@ -1025,7 +1025,7 @@ fn polygon_type_should_fail_on_id() { --> schema.prisma:10  |   9 |  - 10 |  @@id([firstName, lastName]) + 10 |  @@id([a, b])  |  "#]]; @@ -1041,10 +1041,10 @@ fn multipoint_type_should_fail_on_id() { } model User { - firstName GeoJson @db.MultiPoint - lastName GeoJson @db.MultiPoint + a Geometry @db.MultiPoint + b Geometry @db.MultiPoint - @@id([firstName, lastName]) + @@id([a, b]) } "#}; @@ -1053,7 +1053,7 @@ fn multipoint_type_should_fail_on_id() { --> schema.prisma:10  |   9 |  - 10 |  @@id([firstName, lastName]) + 10 |  @@id([a, b])  |  "#]]; @@ -1069,10 +1069,10 @@ fn multilinestring_type_should_fail_on_id() { } model User { - firstName GeoJson @db.MultiLineString - lastName GeoJson @db.MultiLineString + a Geometry @db.MultiLineString + b Geometry @db.MultiLineString - @@id([firstName, lastName]) + @@id([a, b]) } "#}; @@ -1081,7 +1081,7 @@ fn multilinestring_type_should_fail_on_id() { --> schema.prisma:10  |   9 |  - 10 |  @@id([firstName, lastName]) + 10 |  @@id([a, b])  |  "#]]; @@ -1097,10 +1097,10 @@ fn multipolygon_type_should_fail_on_id() { } model User { - firstName GeoJson @db.MultiPolygon - lastName GeoJson @db.MultiPolygon + a Geometry @db.MultiPolygon + b Geometry @db.MultiPolygon - @@id([firstName, lastName]) + @@id([a, b]) } "#}; @@ -1109,7 +1109,7 @@ fn multipolygon_type_should_fail_on_id() { --> schema.prisma:10  |   9 |  - 10 |  @@id([firstName, lastName]) + 10 |  @@id([a, b])  |  "#]]; @@ -1125,10 +1125,10 @@ fn geometrycollection_type_should_fail_on_id() { } model User { - firstName GeoJson @db.GeometryCollection - lastName GeoJson @db.GeometryCollection + a Geometry @db.GeometryCollection + b Geometry @db.GeometryCollection - @@id([firstName, lastName]) + @@id([a, b]) } "#}; @@ -1137,82 +1137,7 @@ fn geometrycollection_type_should_fail_on_id() { --> schema.prisma:10  |   9 |  - 10 |  @@id([firstName, lastName]) -  |  - "#]]; - - expect_error(schema, &expectation); -} - -#[test] -fn geojson_type_should_fail_on_invalid_srid() { - let schema = indoc! {r#" - datasource db { - provider = "mysql" - url = env("DATABASE_URL") - } - - model User { - id Int @id - geom1 GeoJson @db.Geometry(3857) - geom2 GeoJson @db.Point(3857) - geom3 GeoJson @db.LineString(3857) - geom4 GeoJson @db.Polygon(3857) - geom5 GeoJson @db.MultiPoint(3857) - geom6 GeoJson @db.MultiLineString(3857) - geom7 GeoJson @db.MultiPolygon(3857) - geom8 GeoJson @db.GeometryCollection(3857) - } - "#}; - - let expectation = expect![[r#" - error: Argument M is out of range for native type `Geometry(3857)` of MySQL: GeoJson SRID must be 4326. - --> schema.prisma:8 -  |  -  7 |  id Int @id -  8 |  geom1 GeoJson @db.Geometry(3857) -  |  - error: Argument M is out of range for native type `Point(3857)` of MySQL: GeoJson SRID must be 4326. - --> schema.prisma:9 -  |  -  8 |  geom1 GeoJson @db.Geometry(3857) -  9 |  geom2 GeoJson @db.Point(3857) -  |  - error: Argument M is out of range for native type `LineString(3857)` of MySQL: GeoJson SRID must be 4326. - --> schema.prisma:10 -  |  -  9 |  geom2 GeoJson @db.Point(3857) - 10 |  geom3 GeoJson @db.LineString(3857) -  |  - error: Argument M is out of range for native type `Polygon(3857)` of MySQL: GeoJson SRID must be 4326. - --> schema.prisma:11 -  |  - 10 |  geom3 GeoJson @db.LineString(3857) - 11 |  geom4 GeoJson @db.Polygon(3857) -  |  - error: Argument M is out of range for native type `MultiPoint(3857)` of MySQL: GeoJson SRID must be 4326. - --> schema.prisma:12 -  |  - 11 |  geom4 GeoJson @db.Polygon(3857) - 12 |  geom5 GeoJson @db.MultiPoint(3857) -  |  - error: Argument M is out of range for native type `MultiLineString(3857)` of MySQL: GeoJson SRID must be 4326. - --> schema.prisma:13 -  |  - 12 |  geom5 GeoJson @db.MultiPoint(3857) - 13 |  geom6 GeoJson @db.MultiLineString(3857) -  |  - error: Argument M is out of range for native type `MultiPolygon(3857)` of MySQL: GeoJson SRID must be 4326. - --> schema.prisma:14 -  |  - 13 |  geom6 GeoJson @db.MultiLineString(3857) - 14 |  geom7 GeoJson @db.MultiPolygon(3857) -  |  - error: Argument M is out of range for native type `GeometryCollection(3857)` of MySQL: GeoJson SRID must be 4326. - --> schema.prisma:15 -  |  - 14 |  geom7 GeoJson @db.MultiPolygon(3857) - 15 |  geom8 GeoJson @db.GeometryCollection(3857) + 10 |  @@id([a, b])  |  "#]]; diff --git a/psl/psl/tests/types/postgres_native_types.rs b/psl/psl/tests/types/postgres_native_types.rs index 5b6dc567a70f..cfdbc1eb2ac3 100644 --- a/psl/psl/tests/types/postgres_native_types.rs +++ b/psl/psl/tests/types/postgres_native_types.rs @@ -245,341 +245,38 @@ fn postgis_specific_native_types_are_valid() { id Int @id geom_01 Geometry @db.Geometry(Geometry, 4326) geom_02 Geometry @db.Geometry(GeometryZ, 4326) - geom_03 Geometry @db.Geometry(GeometryM, 4326) - geom_04 Geometry @db.Geometry(GeometryZM, 4326) - geom_05 Geometry @db.Geometry(Point, 4326) - geom_06 Geometry @db.Geometry(PointZ, 4326) - geom_07 Geometry @db.Geometry(PointM, 4326) - geom_08 Geometry @db.Geometry(PointZM, 4326) - geom_09 Geometry @db.Geometry(LineString, 4326) - geom_10 Geometry @db.Geometry(LineStringZ, 4326) - geom_11 Geometry @db.Geometry(LineStringM, 4326) - geom_12 Geometry @db.Geometry(LineStringZM, 4326) - geom_13 Geometry @db.Geometry(Polygon, 4326) - geom_14 Geometry @db.Geometry(PolygonZ, 4326) - geom_15 Geometry @db.Geometry(PolygonM, 4326) - geom_16 Geometry @db.Geometry(PolygonZM, 4326) - geom_17 Geometry @db.Geometry(MultiPoint, 4326) - geom_18 Geometry @db.Geometry(MultiPointZ, 4326) - geom_19 Geometry @db.Geometry(MultiPointM, 4326) - geom_20 Geometry @db.Geometry(MultiPointZM, 4326) - geom_21 Geometry @db.Geometry(MultiLineString, 4326) - geom_22 Geometry @db.Geometry(MultiLineStringZ, 4326) - geom_23 Geometry @db.Geometry(MultiLineStringM, 4326) - geom_24 Geometry @db.Geometry(MultiLineStringZM, 4326) - geom_25 Geometry @db.Geometry(MultiPolygon, 4326) - geom_26 Geometry @db.Geometry(MultiPolygonZ, 4326) - geom_27 Geometry @db.Geometry(MultiPolygonM, 4326) - geom_28 Geometry @db.Geometry(MultiPolygonZM, 4326) - geom_29 Geometry @db.Geometry(GeometryCollection, 4326) - geom_30 Geometry @db.Geometry(GeometryCollectionZ, 4326) - geom_31 Geometry @db.Geometry(GeometryCollectionM, 4326) - geom_32 Geometry @db.Geometry(GeometryCollectionZM, 4326) + geom_03 Geometry @db.Geometry(Point, 4326) + geom_04 Geometry @db.Geometry(PointZ, 4326) + geom_05 Geometry @db.Geometry(LineString, 4326) + geom_06 Geometry @db.Geometry(LineStringZ, 4326) + geom_07 Geometry @db.Geometry(Polygon, 4326) + geom_08 Geometry @db.Geometry(PolygonZ, 4326) + geom_09 Geometry @db.Geometry(MultiPoint, 4326) + geom_10 Geometry @db.Geometry(MultiPointZ, 4326) + geom_11 Geometry @db.Geometry(MultiLineString, 4326) + geom_12 Geometry @db.Geometry(MultiLineStringZ, 4326) + geom_13 Geometry @db.Geometry(MultiPolygon, 4326) + geom_14 Geometry @db.Geometry(MultiPolygonZ, 4326) + geom_15 Geometry @db.Geometry(GeometryCollection, 4326) + geom_16 Geometry @db.Geometry(GeometryCollectionZ, 4326) geog_01 Geometry @db.Geography(Geometry, 4326) geog_02 Geometry @db.Geography(GeometryZ, 4326) - geog_03 Geometry @db.Geography(GeometryM, 4326) - geog_04 Geometry @db.Geography(GeometryZM, 4326) - geog_05 Geometry @db.Geography(Point, 4326) - geog_06 Geometry @db.Geography(PointZ, 4326) - geog_07 Geometry @db.Geography(PointM, 4326) - geog_08 Geometry @db.Geography(PointZM, 4326) - geog_09 Geometry @db.Geography(LineString, 4326) - geog_10 Geometry @db.Geography(LineStringZ, 4326) - geog_11 Geometry @db.Geography(LineStringM, 4326) - geog_12 Geometry @db.Geography(LineStringZM, 4326) - geog_13 Geometry @db.Geography(Polygon, 4326) - geog_14 Geometry @db.Geography(PolygonZ, 4326) - geog_15 Geometry @db.Geography(PolygonM, 4326) - geog_16 Geometry @db.Geography(PolygonZM, 4326) - geog_17 Geometry @db.Geography(MultiPoint, 4326) - geog_18 Geometry @db.Geography(MultiPointZ, 4326) - geog_19 Geometry @db.Geography(MultiPointM, 4326) - geog_20 Geometry @db.Geography(MultiPointZM, 4326) - geog_21 Geometry @db.Geography(MultiLineString, 4326) - geog_22 Geometry @db.Geography(MultiLineStringZ, 4326) - geog_23 Geometry @db.Geography(MultiLineStringM, 4326) - geog_24 Geometry @db.Geography(MultiLineStringZM, 4326) - geog_25 Geometry @db.Geography(MultiPolygon, 4326) - geog_26 Geometry @db.Geography(MultiPolygonZ, 4326) - geog_27 Geometry @db.Geography(MultiPolygonM, 4326) - geog_28 Geometry @db.Geography(MultiPolygonZM, 4326) - geog_29 Geometry @db.Geography(GeometryCollection, 4326) - geog_30 Geometry @db.Geography(GeometryCollectionZ, 4326) - geog_31 Geometry @db.Geography(GeometryCollectionM, 4326) - geog_32 Geometry @db.Geography(GeometryCollectionZM, 4326) + geog_03 Geometry @db.Geography(Point, 4326) + geog_04 Geometry @db.Geography(PointZ, 4326) + geog_05 Geometry @db.Geography(LineString, 4326) + geog_06 Geometry @db.Geography(LineStringZ, 4326) + geog_07 Geometry @db.Geography(Polygon, 4326) + geog_08 Geometry @db.Geography(PolygonZ, 4326) + geog_09 Geometry @db.Geography(MultiPoint, 4326) + geog_10 Geometry @db.Geography(MultiPointZ, 4326) + geog_11 Geometry @db.Geography(MultiLineString, 4326) + geog_12 Geometry @db.Geography(MultiLineStringZ, 4326) + geog_13 Geometry @db.Geography(MultiPolygon, 4326) + geog_14 Geometry @db.Geography(MultiPolygonZ, 4326) + geog_15 Geometry @db.Geography(GeometryCollection, 4326) + geog_16 Geometry @db.Geography(GeometryCollectionZ, 4326) } "#}; psl::parse_schema(schema).unwrap(); } - -#[test] -fn should_fail_on_geojson_when_incompatible_geometry_type() { - let dml = indoc! {r#" - datasource db { - provider = "postgres" - url = env("TEST_DATABASE_URL") - } - - model Blog { - id Int @id - geom_01 GeoJson @db.Geometry(GeometryM, 4326) - geom_02 GeoJson @db.Geometry(GeometryZM, 4326) - geom_03 GeoJson @db.Geometry(PointM, 4326) - geom_04 GeoJson @db.Geometry(PointZM, 4326) - geom_05 GeoJson @db.Geometry(PointM, 4326) - geom_06 GeoJson @db.Geometry(PointZM, 4326) - geom_07 GeoJson @db.Geometry(LineStringM, 4326) - geom_08 GeoJson @db.Geometry(LineStringZM, 4326) - geom_09 GeoJson @db.Geometry(PolygonM, 4326) - geom_10 GeoJson @db.Geometry(PolygonZM, 4326) - geom_11 GeoJson @db.Geometry(MultiPointM, 4326) - geom_12 GeoJson @db.Geometry(MultiPointZM, 4326) - geom_13 GeoJson @db.Geometry(MultiLineStringM, 4326) - geom_14 GeoJson @db.Geometry(MultiLineStringZM, 4326) - geom_15 GeoJson @db.Geometry(MultiPolygonM, 4326) - geom_16 GeoJson @db.Geometry(MultiPolygonZM, 4326) - geom_17 GeoJson @db.Geometry(GeometryCollectionM, 4326) - geom_18 GeoJson @db.Geometry(GeometryCollectionZM, 4326) - geog_01 GeoJson @db.Geography(GeometryM, 4326) - geog_02 GeoJson @db.Geography(GeometryZM, 4326) - geog_03 GeoJson @db.Geography(PointM, 4326) - geog_04 GeoJson @db.Geography(PointZM, 4326) - geog_05 GeoJson @db.Geography(PointM, 4326) - geog_06 GeoJson @db.Geography(PointZM, 4326) - geog_07 GeoJson @db.Geography(LineStringM, 4326) - geog_08 GeoJson @db.Geography(LineStringZM, 4326) - geog_09 GeoJson @db.Geography(PolygonM, 4326) - geog_10 GeoJson @db.Geography(PolygonZM, 4326) - geog_11 GeoJson @db.Geography(MultiPointM, 4326) - geog_12 GeoJson @db.Geography(MultiPointZM, 4326) - geog_13 GeoJson @db.Geography(MultiLineStringM, 4326) - geog_14 GeoJson @db.Geography(MultiLineStringZM, 4326) - geog_15 GeoJson @db.Geography(MultiPolygonM, 4326) - geog_16 GeoJson @db.Geography(MultiPolygonZM, 4326) - geog_17 GeoJson @db.Geography(GeometryCollectionM, 4326) - geog_18 GeoJson @db.Geography(GeometryCollectionZM, 4326) - } - "#}; - - let expectation = expect![[r#" - error: Argument M is out of range for native type `Geometry(GeometryM,4326)` of Postgres: GeometryM isn't compatible with GeoJson. - --> schema.prisma:8 -  |  -  7 |  id Int @id -  8 |  geom_01 GeoJson @db.Geometry(GeometryM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(GeometryZM,4326)` of Postgres: GeometryZM isn't compatible with GeoJson. - --> schema.prisma:9 -  |  -  8 |  geom_01 GeoJson @db.Geometry(GeometryM, 4326) -  9 |  geom_02 GeoJson @db.Geometry(GeometryZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(PointM,4326)` of Postgres: PointM isn't compatible with GeoJson. - --> schema.prisma:10 -  |  -  9 |  geom_02 GeoJson @db.Geometry(GeometryZM, 4326) - 10 |  geom_03 GeoJson @db.Geometry(PointM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(PointZM,4326)` of Postgres: PointZM isn't compatible with GeoJson. - --> schema.prisma:11 -  |  - 10 |  geom_03 GeoJson @db.Geometry(PointM, 4326) - 11 |  geom_04 GeoJson @db.Geometry(PointZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(PointM,4326)` of Postgres: PointM isn't compatible with GeoJson. - --> schema.prisma:12 -  |  - 11 |  geom_04 GeoJson @db.Geometry(PointZM, 4326) - 12 |  geom_05 GeoJson @db.Geometry(PointM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(PointZM,4326)` of Postgres: PointZM isn't compatible with GeoJson. - --> schema.prisma:13 -  |  - 12 |  geom_05 GeoJson @db.Geometry(PointM, 4326) - 13 |  geom_06 GeoJson @db.Geometry(PointZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(LineStringM,4326)` of Postgres: LineStringM isn't compatible with GeoJson. - --> schema.prisma:14 -  |  - 13 |  geom_06 GeoJson @db.Geometry(PointZM, 4326) - 14 |  geom_07 GeoJson @db.Geometry(LineStringM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(LineStringZM,4326)` of Postgres: LineStringZM isn't compatible with GeoJson. - --> schema.prisma:15 -  |  - 14 |  geom_07 GeoJson @db.Geometry(LineStringM, 4326) - 15 |  geom_08 GeoJson @db.Geometry(LineStringZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(PolygonM,4326)` of Postgres: PolygonM isn't compatible with GeoJson. - --> schema.prisma:16 -  |  - 15 |  geom_08 GeoJson @db.Geometry(LineStringZM, 4326) - 16 |  geom_09 GeoJson @db.Geometry(PolygonM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(PolygonZM,4326)` of Postgres: PolygonZM isn't compatible with GeoJson. - --> schema.prisma:17 -  |  - 16 |  geom_09 GeoJson @db.Geometry(PolygonM, 4326) - 17 |  geom_10 GeoJson @db.Geometry(PolygonZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiPointM,4326)` of Postgres: MultiPointM isn't compatible with GeoJson. - --> schema.prisma:18 -  |  - 17 |  geom_10 GeoJson @db.Geometry(PolygonZM, 4326) - 18 |  geom_11 GeoJson @db.Geometry(MultiPointM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiPointZM,4326)` of Postgres: MultiPointZM isn't compatible with GeoJson. - --> schema.prisma:19 -  |  - 18 |  geom_11 GeoJson @db.Geometry(MultiPointM, 4326) - 19 |  geom_12 GeoJson @db.Geometry(MultiPointZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiLineStringM,4326)` of Postgres: MultiLineStringM isn't compatible with GeoJson. - --> schema.prisma:20 -  |  - 19 |  geom_12 GeoJson @db.Geometry(MultiPointZM, 4326) - 20 |  geom_13 GeoJson @db.Geometry(MultiLineStringM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiLineStringZM,4326)` of Postgres: MultiLineStringZM isn't compatible with GeoJson. - --> schema.prisma:21 -  |  - 20 |  geom_13 GeoJson @db.Geometry(MultiLineStringM, 4326) - 21 |  geom_14 GeoJson @db.Geometry(MultiLineStringZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiPolygonM,4326)` of Postgres: MultiPolygonM isn't compatible with GeoJson. - --> schema.prisma:22 -  |  - 21 |  geom_14 GeoJson @db.Geometry(MultiLineStringZM, 4326) - 22 |  geom_15 GeoJson @db.Geometry(MultiPolygonM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(MultiPolygonZM,4326)` of Postgres: MultiPolygonZM isn't compatible with GeoJson. - --> schema.prisma:23 -  |  - 22 |  geom_15 GeoJson @db.Geometry(MultiPolygonM, 4326) - 23 |  geom_16 GeoJson @db.Geometry(MultiPolygonZM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(GeometryCollectionM,4326)` of Postgres: GeometryCollectionM isn't compatible with GeoJson. - --> schema.prisma:24 -  |  - 23 |  geom_16 GeoJson @db.Geometry(MultiPolygonZM, 4326) - 24 |  geom_17 GeoJson @db.Geometry(GeometryCollectionM, 4326) -  |  - error: Argument M is out of range for native type `Geometry(GeometryCollectionZM,4326)` of Postgres: GeometryCollectionZM isn't compatible with GeoJson. - --> schema.prisma:25 -  |  - 24 |  geom_17 GeoJson @db.Geometry(GeometryCollectionM, 4326) - 25 |  geom_18 GeoJson @db.Geometry(GeometryCollectionZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(GeometryM,4326)` of Postgres: GeometryM isn't compatible with GeoJson. - --> schema.prisma:26 -  |  - 25 |  geom_18 GeoJson @db.Geometry(GeometryCollectionZM, 4326) - 26 |  geog_01 GeoJson @db.Geography(GeometryM, 4326) -  |  - error: Argument M is out of range for native type `Geography(GeometryZM,4326)` of Postgres: GeometryZM isn't compatible with GeoJson. - --> schema.prisma:27 -  |  - 26 |  geog_01 GeoJson @db.Geography(GeometryM, 4326) - 27 |  geog_02 GeoJson @db.Geography(GeometryZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(PointM,4326)` of Postgres: PointM isn't compatible with GeoJson. - --> schema.prisma:28 -  |  - 27 |  geog_02 GeoJson @db.Geography(GeometryZM, 4326) - 28 |  geog_03 GeoJson @db.Geography(PointM, 4326) -  |  - error: Argument M is out of range for native type `Geography(PointZM,4326)` of Postgres: PointZM isn't compatible with GeoJson. - --> schema.prisma:29 -  |  - 28 |  geog_03 GeoJson @db.Geography(PointM, 4326) - 29 |  geog_04 GeoJson @db.Geography(PointZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(PointM,4326)` of Postgres: PointM isn't compatible with GeoJson. - --> schema.prisma:30 -  |  - 29 |  geog_04 GeoJson @db.Geography(PointZM, 4326) - 30 |  geog_05 GeoJson @db.Geography(PointM, 4326) -  |  - error: Argument M is out of range for native type `Geography(PointZM,4326)` of Postgres: PointZM isn't compatible with GeoJson. - --> schema.prisma:31 -  |  - 30 |  geog_05 GeoJson @db.Geography(PointM, 4326) - 31 |  geog_06 GeoJson @db.Geography(PointZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(LineStringM,4326)` of Postgres: LineStringM isn't compatible with GeoJson. - --> schema.prisma:32 -  |  - 31 |  geog_06 GeoJson @db.Geography(PointZM, 4326) - 32 |  geog_07 GeoJson @db.Geography(LineStringM, 4326) -  |  - error: Argument M is out of range for native type `Geography(LineStringZM,4326)` of Postgres: LineStringZM isn't compatible with GeoJson. - --> schema.prisma:33 -  |  - 32 |  geog_07 GeoJson @db.Geography(LineStringM, 4326) - 33 |  geog_08 GeoJson @db.Geography(LineStringZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(PolygonM,4326)` of Postgres: PolygonM isn't compatible with GeoJson. - --> schema.prisma:34 -  |  - 33 |  geog_08 GeoJson @db.Geography(LineStringZM, 4326) - 34 |  geog_09 GeoJson @db.Geography(PolygonM, 4326) -  |  - error: Argument M is out of range for native type `Geography(PolygonZM,4326)` of Postgres: PolygonZM isn't compatible with GeoJson. - --> schema.prisma:35 -  |  - 34 |  geog_09 GeoJson @db.Geography(PolygonM, 4326) - 35 |  geog_10 GeoJson @db.Geography(PolygonZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiPointM,4326)` of Postgres: MultiPointM isn't compatible with GeoJson. - --> schema.prisma:36 -  |  - 35 |  geog_10 GeoJson @db.Geography(PolygonZM, 4326) - 36 |  geog_11 GeoJson @db.Geography(MultiPointM, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiPointZM,4326)` of Postgres: MultiPointZM isn't compatible with GeoJson. - --> schema.prisma:37 -  |  - 36 |  geog_11 GeoJson @db.Geography(MultiPointM, 4326) - 37 |  geog_12 GeoJson @db.Geography(MultiPointZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiLineStringM,4326)` of Postgres: MultiLineStringM isn't compatible with GeoJson. - --> schema.prisma:38 -  |  - 37 |  geog_12 GeoJson @db.Geography(MultiPointZM, 4326) - 38 |  geog_13 GeoJson @db.Geography(MultiLineStringM, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiLineStringZM,4326)` of Postgres: MultiLineStringZM isn't compatible with GeoJson. - --> schema.prisma:39 -  |  - 38 |  geog_13 GeoJson @db.Geography(MultiLineStringM, 4326) - 39 |  geog_14 GeoJson @db.Geography(MultiLineStringZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiPolygonM,4326)` of Postgres: MultiPolygonM isn't compatible with GeoJson. - --> schema.prisma:40 -  |  - 39 |  geog_14 GeoJson @db.Geography(MultiLineStringZM, 4326) - 40 |  geog_15 GeoJson @db.Geography(MultiPolygonM, 4326) -  |  - error: Argument M is out of range for native type `Geography(MultiPolygonZM,4326)` of Postgres: MultiPolygonZM isn't compatible with GeoJson. - --> schema.prisma:41 -  |  - 40 |  geog_15 GeoJson @db.Geography(MultiPolygonM, 4326) - 41 |  geog_16 GeoJson @db.Geography(MultiPolygonZM, 4326) -  |  - error: Argument M is out of range for native type `Geography(GeometryCollectionM,4326)` of Postgres: GeometryCollectionM isn't compatible with GeoJson. - --> schema.prisma:42 -  |  - 41 |  geog_16 GeoJson @db.Geography(MultiPolygonZM, 4326) - 42 |  geog_17 GeoJson @db.Geography(GeometryCollectionM, 4326) -  |  - error: Argument M is out of range for native type `Geography(GeometryCollectionZM,4326)` of Postgres: GeometryCollectionZM isn't compatible with GeoJson. - --> schema.prisma:43 -  |  - 42 |  geog_17 GeoJson @db.Geography(GeometryCollectionM, 4326) - 43 |  geog_18 GeoJson @db.Geography(GeometryCollectionZM, 4326) -  |  - "#]]; - - expect_error(dml, &expectation); -} diff --git a/psl/psl/tests/types/sqlite_native_types.rs b/psl/psl/tests/types/sqlite_native_types.rs index 6702e28123bb..579bcd01ba93 100644 --- a/psl/psl/tests/types/sqlite_native_types.rs +++ b/psl/psl/tests/types/sqlite_native_types.rs @@ -13,40 +13,22 @@ fn sqlite_specific_native_types_are_valid() { id Int @id geomcol1 Geometry @db.Geometry(Geometry, 4326) geomcol2 Geometry @db.Geometry(GeometryZ, 4326) - geomcol3 Geometry @db.Geometry(GeometryM, 4326) - geomcol4 Geometry @db.Geometry(GeometryZM, 4326) + geomcol3 Geometry @db.Geometry(Point, 4326) + geomcol4 Geometry @db.Geometry(PointZ, 4326) geomcol5 Geometry @db.Geometry(Point, 4326) geomcol6 Geometry @db.Geometry(PointZ, 4326) - geomcol7 Geometry @db.Geometry(PointM, 4326) - geomcol8 Geometry @db.Geometry(PointZM, 4326) - geomcol9 Geometry @db.Geometry(Point, 4326) - geomcol10 Geometry @db.Geometry(PointZ, 4326) - geomcol11 Geometry @db.Geometry(PointM, 4326) - geomcol12 Geometry @db.Geometry(PointZM, 4326) - geomcol13 Geometry @db.Geometry(LineString, 4326) - geomcol14 Geometry @db.Geometry(LineStringZ, 4326) - geomcol15 Geometry @db.Geometry(LineStringM, 4326) - geomcol16 Geometry @db.Geometry(LineStringZM, 4326) - geomcol17 Geometry @db.Geometry(Polygon, 4326) - geomcol18 Geometry @db.Geometry(PolygonZ, 4326) - geomcol19 Geometry @db.Geometry(PolygonM, 4326) - geomcol20 Geometry @db.Geometry(PolygonZM, 4326) - geomcol21 Geometry @db.Geometry(MultiPoint, 4326) - geomcol22 Geometry @db.Geometry(MultiPointZ, 4326) - geomcol23 Geometry @db.Geometry(MultiPointM, 4326) - geomcol24 Geometry @db.Geometry(MultiPointZM, 4326) - geomcol25 Geometry @db.Geometry(MultiLineString, 4326) - geomcol26 Geometry @db.Geometry(MultiLineStringZ, 4326) - geomcol27 Geometry @db.Geometry(MultiLineStringM, 4326) - geomcol28 Geometry @db.Geometry(MultiLineStringZM, 4326) - geomcol29 Geometry @db.Geometry(MultiPolygon, 4326) - geomcol30 Geometry @db.Geometry(MultiPolygonZ, 4326) - geomcol31 Geometry @db.Geometry(MultiPolygonM, 4326) - geomcol32 Geometry @db.Geometry(MultiPolygonZM, 4326) - geomcol33 Geometry @db.Geometry(GeometryCollection, 4326) - geomcol34 Geometry @db.Geometry(GeometryCollectionZ, 4326) - geomcol35 Geometry @db.Geometry(GeometryCollectionM, 4326) - geomcol36 Geometry @db.Geometry(GeometryCollectionZM, 4326) + geomcol7 Geometry @db.Geometry(LineString, 4326) + geomcol8 Geometry @db.Geometry(LineStringZ, 4326) + geomcol9 Geometry @db.Geometry(Polygon, 4326) + geomcol10 Geometry @db.Geometry(PolygonZ, 4326) + geomcol11 Geometry @db.Geometry(MultiPoint, 4326) + geomcol12 Geometry @db.Geometry(MultiPointZ, 4326) + geomcol13 Geometry @db.Geometry(MultiLineString, 4326) + geomcol14 Geometry @db.Geometry(MultiLineStringZ, 4326) + geomcol15 Geometry @db.Geometry(MultiPolygon, 4326) + geomcol16 Geometry @db.Geometry(MultiPolygonZ, 4326) + geomcol17 Geometry @db.Geometry(GeometryCollection, 4326) + geomcol18 Geometry @db.Geometry(GeometryCollectionZ, 4326) } "#}; @@ -54,7 +36,7 @@ fn sqlite_specific_native_types_are_valid() { } #[test] -fn should_fail_on_geojson_when_invalid_geometry_type() { +fn should_fail_on_geometry_when_invalid_geometry_type() { let dml = indoc! {r#" datasource db { provider = "sqlite" @@ -79,32 +61,6 @@ fn should_fail_on_geojson_when_invalid_geometry_type() { expect_error(dml, &expectation); } -#[test] -fn should_fail_on_geojson_when_non_wgs84_srid() { - let schema = indoc! {r#" - datasource db { - provider = "sqlite" - url = "file:test.db" - } - - model User { - id Int @id - geom GeoJson @db.Geometry(Point, 3857) - } - "#}; - - let expectation = expect![[r#" - error: Argument M is out of range for native type `Geometry(Point,3857)` of sqlite: GeoJson SRID must be 4326. - --> schema.prisma:8 -  |  -  7 |  id Int @id -  8 |  geom GeoJson @db.Geometry(Point, 3857) -  |  - "#]]; - - expect_error(schema, &expectation); -} - #[test] fn should_fail_on_geometry_when_out_of_bound_srid() { let schema = indoc! {r#" diff --git a/psl/psl/tests/validation/types/mongodb/invalid_json_usage_in_type.prisma b/psl/psl/tests/validation/types/mongodb/invalid_json_usage_in_type.prisma index 016b4035b553..a6042c040af3 100644 --- a/psl/psl/tests/validation/types/mongodb/invalid_json_usage_in_type.prisma +++ b/psl/psl/tests/validation/types/mongodb/invalid_json_usage_in_type.prisma @@ -17,37 +17,37 @@ model A { b B } -// error: Native type Json is not compatible with declared field type Int, expected field type Json or GeoJson. +// error: Native type Json is not compatible with declared field type Int, expected field type Json or Geometry. // --> schema.prisma:7 //  |  //  6 | type B { //  7 |  a Int @test.Json //  |  -// error: Native type Json is not compatible with declared field type Float, expected field type Json or GeoJson. +// error: Native type Json is not compatible with declared field type Float, expected field type Json or Geometry. // --> schema.prisma:8 //  |  //  7 |  a Int @test.Json //  8 |  b Float @test.Json //  |  -// error: Native type Json is not compatible with declared field type Bytes, expected field type Json or GeoJson. +// error: Native type Json is not compatible with declared field type Bytes, expected field type Json or Geometry. // --> schema.prisma:9 //  |  //  8 |  b Float @test.Json //  9 |  c Bytes @test.Json //  |  -// error: Native type Json is not compatible with declared field type Boolean, expected field type Json or GeoJson. +// error: Native type Json is not compatible with declared field type Boolean, expected field type Json or Geometry. // --> schema.prisma:10 //  |  //  9 |  c Bytes @test.Json // 10 |  d Boolean @test.Json //  |  -// error: Native type Json is not compatible with declared field type DateTime, expected field type Json or GeoJson. +// error: Native type Json is not compatible with declared field type DateTime, expected field type Json or Geometry. // --> schema.prisma:11 //  |  // 10 |  d Boolean @test.Json // 11 |  e DateTime @test.Json //  |  -// error: Native type Json is not compatible with declared field type Decimal, expected field type Json or GeoJson. +// error: Native type Json is not compatible with declared field type Decimal, expected field type Json or Geometry. // --> schema.prisma:12 //  |  // 11 |  e DateTime @test.Json diff --git a/quaint/src/connector/mysql/native/conversion.rs b/quaint/src/connector/mysql/native/conversion.rs index db9836f34988..7a57ea6908c0 100644 --- a/quaint/src/connector/mysql/native/conversion.rs +++ b/quaint/src/connector/mysql/native/conversion.rs @@ -69,13 +69,23 @@ pub fn conv_params(params: &[Value<'_>]) -> crate::Result { dt.timestamp_subsec_micros(), ) }), - ValueType::Geometry(g) | ValueType::Geography(g) => g.as_ref().map(|g| { - // TODO@geometry: Improve WKB serialization error handling - WktStr(&g.wkt) - .to_mysql_wkb(Some(g.srid)) - .map(my::Value::Bytes) - .unwrap_or_else(|_| panic!("Couldn't convert value `{g}` into EWKB.")) - }), + ValueType::Geometry(g) | ValueType::Geography(g) => match g { + None => None, + Some(ref g) => { + let res = WktStr(&g.wkt).to_mysql_wkb(Some(g.srid)).map(my::Value::Bytes); + + if res.is_err() { + let msg = "Couldn't convert value `{g}` into EWKB."; + let kind = ErrorKind::conversion(msg); + + let mut builder = Error::builder(kind); + builder.set_original_message(msg); + + return Err(builder.build()); + } + Some(res.unwrap()) + } + }, }; match res { diff --git a/quaint/src/visitor/mysql.rs b/quaint/src/visitor/mysql.rs index f60c92227bd9..47a7b7b8d6c7 100644 --- a/quaint/src/visitor/mysql.rs +++ b/quaint/src/visitor/mysql.rs @@ -311,9 +311,17 @@ impl<'a> Visitor<'a> for Mysql<'a> { } } + /// MySQL geometries *must* be handled in raw binary form to prevent it from swapping longitude and latitude fn visit_parameterized(&mut self, value: Value<'a>) -> visitor::Result { - self.add_parameter(value); - self.parameter_substitution() + match value.typed { + ValueType::Enum(Some(variant), name) => self.visit_parameterized_enum(variant, name), + ValueType::EnumArray(Some(variants), name) => self.visit_parameterized_enum_array(variants, name), + ValueType::Text(txt) => self.visit_parameterized_text(txt, value.native_column_type), + _ => { + self.add_parameter(value); + self.parameter_substitution() + } + } } fn parameter_substitution(&mut self) -> visitor::Result { diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs index c60f8d0ce316..ae8f3c8aaf4c 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs @@ -1,6 +1,6 @@ use query_engine_tests::*; -#[test_suite(capabilities(GeoJsonGeometry))] +#[test_suite(capabilities(Geometry))] mod geometry_filter_spec { use query_engine_tests::run_query; @@ -9,7 +9,7 @@ mod geometry_filter_spec { r#" model TestModel { #id(id, Int, @id) - geom GeoJson? + geom Geometry? } "# }; @@ -23,7 +23,7 @@ mod geometry_filter_spec { model TestModel { @@schema("test") #id(id, Int, @id) - geom GeoJson? + geom Geometry? } "# }; diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mongodb.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mongodb.rs index b7d13e757d05..80f28e9e855d 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mongodb.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mongodb.rs @@ -17,7 +17,7 @@ mod mongodb { bool Boolean @test.Bool bin Bytes @test.BinData bin_oid Bytes @test.ObjectId - geom GeoJson + geom Geometry }"# }; diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs index dd3bcee94d98..aaec4296a9c5 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs @@ -431,69 +431,18 @@ mod mysql { Ok(()) } - fn schema_ewkt_geometry_types() -> String { - let schema = indoc! { - r#"model Model { - #id(id, String, @id, @default(cuid())) - geometry Geometry @test.Geometry - point Geometry @test.Point - line Geometry @test.LineString - poly Geometry @test.Polygon - multipoint Geometry @test.MultiPoint - multiline Geometry @test.MultiLineString - multipoly Geometry @test.MultiPolygon - collection Geometry @test.GeometryCollection - }"# - }; - - schema.to_owned() - } - - // "MySQL native spatial types" should "work" - #[connector_test(schema(schema_ewkt_geometry_types))] - async fn native_ewkt_geometry_types(runner: Runner) -> TestResult<()> { - insta::assert_snapshot!( - run_query!(&runner, r#"mutation { - createOneModel( - data: { - geometry: "POINT(1 2)" - point: "POINT(1 2)" - line: "LINESTRING(1 2,3 4)" - poly: "POLYGON((1 2,3 4,5 6,1 2))" - multipoint: "MULTIPOINT(1 2)" - multiline: "MULTILINESTRING((1 2,3 4))" - multipoly: "MULTIPOLYGON(((1 2,3 4,5 6,1 2)))" - collection: "GEOMETRYCOLLECTION(POINT(1 2))" - } - ) { - geometry, - point - line - poly - multipoint - multiline - multipoly - collection - } - }"#), - @r###"{"data":{"createOneModel":{"geometry":"POINT(1 2)","point":"POINT(1 2)","line":"LINESTRING(1 2,3 4)","poly":"POLYGON((1 2,3 4,5 6,1 2))","multipoint":"MULTIPOINT(1 2)","multiline":"MULTILINESTRING((1 2,3 4))","multipoly":"MULTIPOLYGON(((1 2,3 4,5 6,1 2)))","collection":"GEOMETRYCOLLECTION(POINT(1 2))"}}}"### - ); - - Ok(()) - } - - fn schema_geojson_geometry_types() -> String { + fn schema_geometry_types() -> String { let schema = indoc! { r#"model Model { #id(id, String, @id, @default(cuid())) - geometry GeoJson @test.Geometry - point GeoJson @test.Point - line GeoJson @test.LineString - poly GeoJson @test.Polygon - multipoint GeoJson @test.MultiPoint - multiline GeoJson @test.MultiLineString - multipoly GeoJson @test.MultiPolygon - collection GeoJson @test.GeometryCollection + geometry Geometry @test.Geometry + point Geometry @test.Point + line Geometry @test.LineString + poly Geometry @test.Polygon + multipoint Geometry @test.MultiPoint + multiline Geometry @test.MultiLineString + multipoly Geometry @test.MultiPolygon + collection Geometry @test.GeometryCollection }"# }; @@ -501,20 +450,20 @@ mod mysql { } // "MySQL native spatial types" should "work" - #[connector_test(schema(schema_geojson_geometry_types))] - async fn native_geojson_geometry_types(runner: Runner) -> TestResult<()> { + #[connector_test(schema(schema_geometry_types))] + async fn native_geometry_types(runner: Runner) -> TestResult<()> { insta::assert_snapshot!( run_query!(&runner, r#"mutation { createOneModel( data: { - geometry: "{\"type\":\"Point\",\"coordinates\":[1,2]}" - point: "{\"type\":\"Point\",\"coordinates\":[1,2]}" - line: "{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}" - poly: "{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}" - multipoint: "{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}" - multiline: "{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}" - multipoly: "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}" - collection: "{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}" + geometry: "{\"type\": \"Point\", \"coordinates\" :[1,2]}" + point: "{\"type\": \"Point\", \"coordinates\" :[1,2]}" + line: "{\"type\": \"LineString\", \"coordinates\" :[[1,2],[3,4]]}" + poly: "{\"type\": \"Polygon\", \"coordinates\" :[[[1,2],[3,4],[5,6],[1,2]]]}" + multipoint: "{\"type\": \"MultiPoint\", \"coordinates\" :[[1,2]]}" + multiline: "{\"type\": \"MultiLineString\", \"coordinates\" :[[[1,2],[3,4]]]}" + multipoly: "{\"type\": \"MultiPolygon\", \"coordinates\" :[[[[1,2],[3,4],[5,6],[1,2]]]]}" + collection: "{\"type\": \"GeometryCollection\",\"geometries\" :[{\"type\": \"Point\", \"coordinates\" :[1,2]}]}" } ) { geometry, @@ -534,68 +483,17 @@ mod mysql { } fn schema_geometry_srid_types() -> String { - let schema = indoc! { - r#"model Model { - #id(id, String, @id, @default(cuid())) - geometry Geometry @test.Geometry(4326) - point Geometry @test.Point(4326) - line Geometry @test.LineString(4326) - poly Geometry @test.Polygon(4326) - multipoint Geometry @test.MultiPoint(4326) - multiline Geometry @test.MultiLineString(4326) - multipoly Geometry @test.MultiPolygon(4326) - collection Geometry @test.GeometryCollection(4326) - }"# - }; - - schema.to_owned() - } - - // "MySQL native spatial srid types" should "work" - #[connector_test(only(MySQL(8)), schema(schema_geometry_srid_types))] - async fn native_geometry_srid_types(runner: Runner) -> TestResult<()> { - insta::assert_snapshot!( - run_query!(&runner, r#"mutation { - createOneModel( - data: { - geometry: "SRID=4326;POINT(1 2)" - point: "SRID=4326;POINT(1 2)" - line: "SRID=4326;LINESTRING(1 2,3 4)" - poly: "SRID=4326;POLYGON((1 2,3 4,5 6,1 2))" - multipoint: "SRID=4326;MULTIPOINT(1 2)" - multiline: "SRID=4326;MULTILINESTRING((1 2,3 4))" - multipoly: "SRID=4326;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))" - collection: "SRID=4326;GEOMETRYCOLLECTION(POINT(1 2))" - } - ) { - geometry - point - line - poly - multipoint - multiline - multipoly - collection - } - }"#), - @r###"{"data":{"createOneModel":{"geometry":"SRID=4326;POINT(1 2)","point":"SRID=4326;POINT(1 2)","line":"SRID=4326;LINESTRING(1 2,3 4)","poly":"SRID=4326;POLYGON((1 2,3 4,5 6,1 2))","multipoint":"SRID=4326;MULTIPOINT(1 2)","multiline":"SRID=4326;MULTILINESTRING((1 2,3 4))","multipoly":"SRID=4326;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))","collection":"SRID=4326;GEOMETRYCOLLECTION(POINT(1 2))"}}}"### - ); - - Ok(()) - } - - fn schema_geojson_srid_geometry_types() -> String { let schema = indoc! { r#"model Model { #id(id, String, @id, @default(cuid())) - geometry GeoJson @test.Geometry(4326) - point GeoJson @test.Point(4326) - line GeoJson @test.LineString(4326) - poly GeoJson @test.Polygon(4326) - multipoint GeoJson @test.MultiPoint(4326) - multiline GeoJson @test.MultiLineString(4326) - multipoly GeoJson @test.MultiPolygon(4326) - collection GeoJson @test.GeometryCollection(4326) + geometry Geometry @test.Geometry(3857) + point Geometry @test.Point(3857) + line Geometry @test.LineString(3857) + poly Geometry @test.Polygon(3857) + multipoint Geometry @test.MultiPoint(3857) + multiline Geometry @test.MultiLineString(3857) + multipoly Geometry @test.MultiPolygon(3857) + collection Geometry @test.GeometryCollection(3857) }"# }; @@ -603,20 +501,20 @@ mod mysql { } // "MySQL native spatial types" should "work" - #[connector_test(only(MySQL(8)), schema(schema_geojson_srid_geometry_types))] - async fn native_geojson_srid_geometry_types(runner: Runner) -> TestResult<()> { + #[connector_test(only(MySQL(8)), schema(schema_geometry_srid_types))] + async fn native_geometry_srid_types(runner: Runner) -> TestResult<()> { insta::assert_snapshot!( run_query!(&runner, r#"mutation { createOneModel( data: { - geometry: "{\"type\":\"Point\",\"coordinates\":[1,2]}" - point: "{\"type\":\"Point\",\"coordinates\":[1,2]}" - line: "{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}" - poly: "{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}" - multipoint: "{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}" - multiline: "{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}" - multipoly: "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}" - collection: "{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}" + geometry: "{\"type\": \"Point\", \"coordinates\" :[1,2]}" + point: "{\"type\": \"Point\", \"coordinates\" :[1,2]}" + line: "{\"type\": \"LineString\", \"coordinates\" :[[1,2],[3,4]]}" + poly: "{\"type\": \"Polygon\", \"coordinates\" :[[[1,2],[3,4],[5,6],[1,2]]]}" + multipoint: "{\"type\": \"MultiPoint\", \"coordinates\" :[[1,2]]}" + multiline: "{\"type\": \"MultiLineString\", \"coordinates\" :[[[1,2],[3,4]]]}" + multipoly: "{\"type\": \"MultiPolygon\", \"coordinates\" :[[[[1,2],[3,4],[5,6],[1,2]]]]}" + collection: "{\"type\": \"GeometryCollection\",\"geometries\" :[{\"type\": \"Point\", \"coordinates\" :[1,2]}]}" } ) { geometry, diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/postgres.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/postgres.rs index ccb300d0f676..b4452f4e14a8 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/postgres.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/postgres.rs @@ -347,7 +347,7 @@ mod postgres { Ok(()) } - fn schema_ewkt_geometry() -> String { + fn schema_geometry() -> String { let schema = indoc! { r#"model Model { @@schema("test") @@ -369,22 +369,22 @@ mod postgres { // "PostGIS common geometry types" should "work" #[connector_test( only(Postgres("16-postgis"), CockroachDb), - schema(schema_ewkt_geometry), + schema(schema_geometry), db_schemas("public", "test") )] - async fn native_ewkt_geometry(runner: Runner) -> TestResult<()> { + async fn native_geometry(runner: Runner) -> TestResult<()> { insta::assert_snapshot!( run_query!(&runner, r#"mutation { createOneModel( data: { - geometry: "POINT(1 2)" - geometry_point: "POINT(1 2)" - geometry_line: "LINESTRING(1 2,3 4)" - geometry_poly: "POLYGON((1 2,3 4,5 6,1 2))" - geometry_multipoint: "MULTIPOINT(1 2)" - geometry_multiline: "MULTILINESTRING((1 2,3 4))" - geometry_multipoly: "MULTIPOLYGON(((1 2,3 4,5 6,1 2)))" - geometry_collection: "GEOMETRYCOLLECTION(POINT(1 2))" + geometry: "{\"type\":\"Point\",\"coordinates\":[1,2]}" + geometry_point: "{\"type\":\"Point\",\"coordinates\":[1,2]}" + geometry_line: "{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}" + geometry_poly: "{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}" + geometry_multipoint: "{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}" + geometry_multiline: "{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}" + geometry_multipoly: "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}" + geometry_collection: "{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}" } ) { geometry @@ -397,13 +397,13 @@ mod postgres { geometry_collection } }"#), - @r###"{"data":{"createOneModel":{"geometry":"POINT(1 2)","geometry_point":"POINT(1 2)","geometry_line":"LINESTRING(1 2,3 4)","geometry_poly":"POLYGON((1 2,3 4,5 6,1 2))","geometry_multipoint":"MULTIPOINT(1 2)","geometry_multiline":"MULTILINESTRING((1 2,3 4))","geometry_multipoly":"MULTIPOLYGON(((1 2,3 4,5 6,1 2)))","geometry_collection":"GEOMETRYCOLLECTION(POINT(1 2))"}}}"### + @r###"{"data":{"createOneModel":{"geometry":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geometry_point":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geometry_line":"{\"type\": \"LineString\", \"coordinates\": [[1,2],[3,4]]}","geometry_poly":"{\"type\": \"Polygon\", \"coordinates\": [[[1,2],[3,4],[5,6],[1,2]]]}","geometry_multipoint":"{\"type\": \"MultiPoint\", \"coordinates\": [[1,2]]}","geometry_multiline":"{\"type\": \"MultiLineString\", \"coordinates\": [[[1,2],[3,4]]]}","geometry_multipoly":"{\"type\": \"MultiPolygon\", \"coordinates\": [[[[1,2],[3,4],[5,6],[1,2]]]]}","geometry_collection":"{\"type\": \"GeometryCollection\", \"geometries\": [{\"type\": \"Point\", \"coordinates\": [1,2]}]}"}}}"### ); Ok(()) } - fn schema_ewkt_geometry_srid() -> String { + fn schema_geometry_srid() -> String { let schema = indoc! { r#"model Model { @@schema("test") @@ -425,7 +425,7 @@ mod postgres { // "PostGIS common geometry types with srid" should "work" #[connector_test( only(Postgres("16-postgis"), CockroachDb), - schema(schema_ewkt_geometry_srid), + schema(schema_geometry_srid), db_schemas("public", "test") )] async fn native_geometry_srid(runner: Runner) -> TestResult<()> { @@ -433,14 +433,14 @@ mod postgres { run_query!(&runner, r#"mutation { createOneModel( data: { - geometry: "SRID=3857;POINT(1 2)" - geometry_point: "SRID=3857;POINT(1 2)" - geometry_line: "SRID=3857;LINESTRING(1 2,3 4)" - geometry_poly: "SRID=3857;POLYGON((1 2,3 4,5 6,1 2))" - geometry_multipoint: "SRID=3857;MULTIPOINT(1 2)" - geometry_multiline: "SRID=3857;MULTILINESTRING((1 2,3 4))" - geometry_multipoly: "SRID=3857;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))" - geometry_collection: "SRID=3857;GEOMETRYCOLLECTION(POINT(1 2))" + geometry: "{\"type\":\"Point\",\"coordinates\":[1,2]}" + geometry_point: "{\"type\":\"Point\",\"coordinates\":[1,2]}" + geometry_line: "{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}" + geometry_poly: "{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}" + geometry_multipoint: "{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}" + geometry_multiline: "{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}" + geometry_multipoly: "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}" + geometry_collection: "{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}" } ) { geometry @@ -453,13 +453,13 @@ mod postgres { geometry_collection } }"#), - @r###"{"data":{"createOneModel":{"geometry":"SRID=3857;POINT(1 2)","geometry_point":"SRID=3857;POINT(1 2)","geometry_line":"SRID=3857;LINESTRING(1 2,3 4)","geometry_poly":"SRID=3857;POLYGON((1 2,3 4,5 6,1 2))","geometry_multipoint":"SRID=3857;MULTIPOINT(1 2)","geometry_multiline":"SRID=3857;MULTILINESTRING((1 2,3 4))","geometry_multipoly":"SRID=3857;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))","geometry_collection":"SRID=3857;GEOMETRYCOLLECTION(POINT(1 2))"}}}"### + @r###"{"data":{"createOneModel":{"geometry":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geometry_point":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geometry_line":"{\"type\": \"LineString\", \"coordinates\": [[1,2],[3,4]]}","geometry_poly":"{\"type\": \"Polygon\", \"coordinates\": [[[1,2],[3,4],[5,6],[1,2]]]}","geometry_multipoint":"{\"type\": \"MultiPoint\", \"coordinates\": [[1,2]]}","geometry_multiline":"{\"type\": \"MultiLineString\", \"coordinates\": [[[1,2],[3,4]]]}","geometry_multipoly":"{\"type\": \"MultiPolygon\", \"coordinates\": [[[[1,2],[3,4],[5,6],[1,2]]]]}","geometry_collection":"{\"type\": \"GeometryCollection\", \"geometries\": [{\"type\": \"Point\", \"coordinates\": [1,2]}]}"}}}"### ); Ok(()) } - fn schema_ewkt_geography() -> String { + fn schema_geography() -> String { let schema = indoc! { r#"model Model { @@schema("test") @@ -481,22 +481,22 @@ mod postgres { // "PostGIS common geography types" should "work" #[connector_test( only(Postgres("16-postgis"), CockroachDb), - schema(schema_ewkt_geography), + schema(schema_geography), db_schemas("public", "test") )] - async fn native_ewkt_geography(runner: Runner) -> TestResult<()> { + async fn native_geography(runner: Runner) -> TestResult<()> { insta::assert_snapshot!( run_query!(&runner, r#"mutation { createOneModel( data: { - geography: "SRID=4326;POINT(1 2)" - geography_point: "SRID=4326;POINT(1 2)" - geography_line: "SRID=4326;LINESTRING(1 2,3 4)" - geography_poly: "SRID=4326;POLYGON((1 2,3 4,5 6,1 2))" - geography_multipoint: "SRID=4326;MULTIPOINT(1 2)" - geography_multiline: "SRID=4326;MULTILINESTRING((1 2,3 4))" - geography_multipoly: "SRID=4326;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))" - geography_collection: "SRID=4326;GEOMETRYCOLLECTION(POINT(1 2))" + geography: "{\"type\":\"Point\",\"coordinates\":[1,2]}" + geography_point: "{\"type\":\"Point\",\"coordinates\":[1,2]}" + geography_line: "{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}" + geography_poly: "{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}" + geography_multipoint: "{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}" + geography_multiline: "{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}" + geography_multipoly: "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}" + geography_collection: "{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}" } ) { geography @@ -509,13 +509,13 @@ mod postgres { geography_collection } }"#), - @r###"{"data":{"createOneModel":{"geography":"SRID=4326;POINT(1 2)","geography_point":"SRID=4326;POINT(1 2)","geography_line":"SRID=4326;LINESTRING(1 2,3 4)","geography_poly":"SRID=4326;POLYGON((1 2,3 4,5 6,1 2))","geography_multipoint":"SRID=4326;MULTIPOINT(1 2)","geography_multiline":"SRID=4326;MULTILINESTRING((1 2,3 4))","geography_multipoly":"SRID=4326;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))","geography_collection":"SRID=4326;GEOMETRYCOLLECTION(POINT(1 2))"}}}"### + @r###"{"data":{"createOneModel":{"geography":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geography_point":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geography_line":"{\"type\": \"LineString\", \"coordinates\": [[1,2],[3,4]]}","geography_poly":"{\"type\": \"Polygon\", \"coordinates\": [[[1,2],[3,4],[5,6],[1,2]]]}","geography_multipoint":"{\"type\": \"MultiPoint\", \"coordinates\": [[1,2]]}","geography_multiline":"{\"type\": \"MultiLineString\", \"coordinates\": [[[1,2],[3,4]]]}","geography_multipoly":"{\"type\": \"MultiPolygon\", \"coordinates\": [[[[1,2],[3,4],[5,6],[1,2]]]]}","geography_collection":"{\"type\": \"GeometryCollection\", \"geometries\": [{\"type\": \"Point\", \"coordinates\": [1,2]}]}"}}}"### ); Ok(()) } - fn schema_ewkt_geography_srid() -> String { + fn schema_geography_srid() -> String { let schema = indoc! { r#"model Model { @@schema("test") @@ -537,122 +537,10 @@ mod postgres { // "PostGIS common geography types with srid" should "work" #[connector_test( only(Postgres("16-postgis"), CockroachDb), - schema(schema_ewkt_geography_srid), - db_schemas("public", "test") - )] - async fn native_ewkt_geography_srid(runner: Runner) -> TestResult<()> { - insta::assert_snapshot!( - run_query!(&runner, r#"mutation { - createOneModel( - data: { - geography: "SRID=9000;POINT(1 2)" - geography_point: "SRID=9000;POINT(1 2)" - geography_line: "SRID=9000;LINESTRING(1 2,3 4)" - geography_poly: "SRID=9000;POLYGON((1 2,3 4,5 6,1 2))" - geography_multipoint: "SRID=9000;MULTIPOINT(1 2)" - geography_multiline: "SRID=9000;MULTILINESTRING((1 2,3 4))" - geography_multipoly: "SRID=9000;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))" - geography_collection: "SRID=9000;GEOMETRYCOLLECTION(POINT(1 2))" - } - ) { - geography - geography_point - geography_line - geography_poly - geography_multipoint - geography_multiline - geography_multipoly - geography_collection - } - }"#), - @r###"{"data":{"createOneModel":{"geography":"SRID=9000;POINT(1 2)","geography_point":"SRID=9000;POINT(1 2)","geography_line":"SRID=9000;LINESTRING(1 2,3 4)","geography_poly":"SRID=9000;POLYGON((1 2,3 4,5 6,1 2))","geography_multipoint":"SRID=9000;MULTIPOINT(1 2)","geography_multiline":"SRID=9000;MULTILINESTRING((1 2,3 4))","geography_multipoly":"SRID=9000;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))","geography_collection":"SRID=9000;GEOMETRYCOLLECTION(POINT(1 2))"}}}"### - ); - - Ok(()) - } - - fn schema_geojson_geometry() -> String { - let schema = indoc! { - r#"model Model { - @@schema("test") - #id(id, String, @id, @default(cuid())) - geometry GeoJson @test.Geometry(Geometry, 4326) - geometry_point GeoJson @test.Geometry(Point, 4326) - geometry_line GeoJson @test.Geometry(LineString, 4326) - geometry_poly GeoJson @test.Geometry(Polygon, 4326) - geometry_multipoint GeoJson @test.Geometry(MultiPoint, 4326) - geometry_multiline GeoJson @test.Geometry(MultiLineString, 4326) - geometry_multipoly GeoJson @test.Geometry(MultiPolygon, 4326) - geometry_collection GeoJson @test.Geometry(GeometryCollection, 4326) - }"# - }; - - schema.to_owned() - } - - // "PostGIS common geometry types" should "work" with GeoJSON - #[connector_test( - only(Postgres("16-postgis"), CockroachDb), - schema(schema_geojson_geometry), - db_schemas("public", "test") - )] - async fn native_geojson_geometry(runner: Runner) -> TestResult<()> { - insta::assert_snapshot!( - run_query!(&runner, r#"mutation { - createOneModel( - data: { - geometry: "{\"type\":\"Point\",\"coordinates\":[1,2]}" - geometry_point: "{\"type\":\"Point\",\"coordinates\":[1,2]}" - geometry_line: "{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}" - geometry_poly: "{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}" - geometry_multipoint: "{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}" - geometry_multiline: "{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}" - geometry_multipoly: "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}" - geometry_collection: "{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}" - } - ) { - geometry - geometry_point - geometry_line - geometry_poly - geometry_multipoint - geometry_multiline - geometry_multipoly - geometry_collection - } - }"#), - @r###"{"data":{"createOneModel":{"geometry":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geometry_point":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geometry_line":"{\"type\": \"LineString\", \"coordinates\": [[1,2],[3,4]]}","geometry_poly":"{\"type\": \"Polygon\", \"coordinates\": [[[1,2],[3,4],[5,6],[1,2]]]}","geometry_multipoint":"{\"type\": \"MultiPoint\", \"coordinates\": [[1,2]]}","geometry_multiline":"{\"type\": \"MultiLineString\", \"coordinates\": [[[1,2],[3,4]]]}","geometry_multipoly":"{\"type\": \"MultiPolygon\", \"coordinates\": [[[[1,2],[3,4],[5,6],[1,2]]]]}","geometry_collection":"{\"type\": \"GeometryCollection\", \"geometries\": [{\"type\": \"Point\", \"coordinates\": [1,2]}]}"}}}"### - ); - - Ok(()) - } - - fn schema_geojson_geography() -> String { - let schema = indoc! { - r#"model Model { - @@schema("test") - #id(id, String, @id, @default(cuid())) - geography GeoJson @test.Geography(Geometry, 4326) - geography_point GeoJson @test.Geography(Point, 4326) - geography_line GeoJson @test.Geography(LineString, 4326) - geography_poly GeoJson @test.Geography(Polygon, 4326) - geography_multipoint GeoJson @test.Geography(MultiPoint, 4326) - geography_multiline GeoJson @test.Geography(MultiLineString, 4326) - geography_multipoly GeoJson @test.Geography(MultiPolygon, 4326) - geography_collection GeoJson @test.Geography(GeometryCollection, 4326) - }"# - }; - - schema.to_owned() - } - - // "PostGIS common geometry types" should "work" with GeoJSON - #[connector_test( - only(Postgres("16-postgis"), CockroachDb), - schema(schema_geojson_geography), + schema(schema_geography_srid), db_schemas("public", "test") )] - async fn native_geojson_geography(runner: Runner) -> TestResult<()> { + async fn native_geography_srid(runner: Runner) -> TestResult<()> { insta::assert_snapshot!( run_query!(&runner, r#"mutation { createOneModel( @@ -677,7 +565,7 @@ mod postgres { geography_collection } }"#), - @r###"{"data":{"createOneModel":{"geography":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geography_point":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geography_line":"{\"type\": \"LineString\", \"coordinates\": [[1,2],[3,4]]}","geography_poly":"{\"type\": \"Polygon\", \"coordinates\": [[[1,2],[3,4],[5,6],[1,2]]]}","geography_multipoint":"{\"type\": \"MultiPoint\", \"coordinates\": [[1,2]]}","geography_multiline":"{\"type\": \"MultiLineString\", \"coordinates\": [[[1,2],[3,4]]]}","geography_multipoly":"{\"type\": \"MultiPolygon\", \"coordinates\": [[[[1,2],[3,4],[5,6],[1,2]]]]}","geography_collection":"{\"type\": \"GeometryCollection\", \"geometries\": [{\"type\": \"Point\", \"coordinates\": [1,2]}]}"}}}"### + @r###"{"data":{"createOneModel":{"geography":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geography_point":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geography_line":"{\"type\": \"LineString\", \"coordinates\": [[1,2],[3,4]]}","geography_poly":"{\"type\": \"Polygon\", \"coordinates\": [[[1,2],[3,4],[5,6],[1,2]]]}","geography_multipoint":"{\"type\": \"MultiPoint\", \"coordinates\": [[1,2]]}","geography_multiline":"{\"type\": \"MultiLineString\", \"coordinates\": [[[1,2],[3,4]]]}","geography_multipoly":"{\"type\": \"MultiPolygon\", \"coordinates\": [[[[1,2],[3,4],[5,6],[1,2]]]]}","geography_collection":"{\"type\": \"GeometryCollection\", \"geometries\": [{\"type\": \"Point\", \"coordinates\": [1,2]}]}"}}}"### ); Ok(()) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sql_server.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sql_server.rs index 38dabaec7fa0..12593d38f482 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sql_server.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sql_server.rs @@ -380,8 +380,8 @@ mod sql_server { data: { xml: "purr" uuid: "ab309dfd-d041-4110-b162-75d7b95fe989" - geom: "SRID=4326;POINT(1 2)" - geog: "SRID=4326;POINT(1 2)" + geom: "{\"type\": \"Point\", \"coordinates\": [1,2]}" + geog: "{\"type\": \"Point\", \"coordinates\": [1,2]}" } ) { xml @@ -390,7 +390,7 @@ mod sql_server { geog } }"#), - @r###"{"data":{"createOneModel":{"xml":"purr","uuid":"ab309dfd-d041-4110-b162-75d7b95fe989","geom":"SRID=4326;POINT (1 2)","geog":"SRID=4326;POINT (1 2)"}}}"### + @r###"{"data":{"createOneModel":{"xml":"purr","uuid":"ab309dfd-d041-4110-b162-75d7b95fe989","geom":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geog":"{\"type\": \"Point\", \"coordinates\": [1,2]}"}}}"### ); Ok(()) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sqlite.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sqlite.rs index 5d7a338c98ab..770eb1d8b96a 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sqlite.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sqlite.rs @@ -5,39 +5,39 @@ mod sqlite { use indoc::indoc; use query_engine_tests::run_query; - fn schema_ewkt_geometry() -> String { + fn schema_geometry() -> String { let schema = indoc! { r#"model Model { #id(id, String, @id, @default(cuid())) - geometry Geometry @test.Geometry(Geometry) - geometry_point Geometry @test.Geometry(Point) - geometry_line Geometry @test.Geometry(LineString) - geometry_poly Geometry @test.Geometry(Polygon) - geometry_multipoint Geometry @test.Geometry(MultiPoint) - geometry_multiline Geometry @test.Geometry(MultiLineString) - geometry_multipoly Geometry @test.Geometry(MultiPolygon) - geometry_collection Geometry @test.Geometry(GeometryCollection) + geometry Geometry @test.Geometry(Geometry, 4326) + geometry_point Geometry @test.Geometry(Point, 4326) + geometry_line Geometry @test.Geometry(LineString, 4326) + geometry_poly Geometry @test.Geometry(Polygon, 4326) + geometry_multipoint Geometry @test.Geometry(MultiPoint, 4326) + geometry_multiline Geometry @test.Geometry(MultiLineString, 4326) + geometry_multipoly Geometry @test.Geometry(MultiPolygon, 4326) + geometry_collection Geometry @test.Geometry(GeometryCollection, 4326) }"# }; schema.to_owned() } - // "Spatialite common geometry types" should "work" - #[connector_test(schema(schema_ewkt_geometry))] - async fn native_ewkt_geometry(runner: Runner) -> TestResult<()> { + // "Spatialite geometry types" should "work" + #[connector_test(schema(schema_geometry))] + async fn native_geometry(runner: Runner) -> TestResult<()> { insta::assert_snapshot!( run_query!(&runner, r#"mutation { createOneModel( data: { - geometry: "POINT(1 2)" - geometry_point: "POINT(1 2)" - geometry_line: "LINESTRING(1 2,3 4)" - geometry_poly: "POLYGON((1 2,3 4,5 6,1 2))" - geometry_multipoint: "MULTIPOINT(1 2)" - geometry_multiline: "MULTILINESTRING((1 2,3 4))" - geometry_multipoly: "MULTIPOLYGON(((1 2,3 4,5 6,1 2)))" - geometry_collection: "GEOMETRYCOLLECTION(POINT(1 2))" + geometry: "{\"type\":\"Point\",\"coordinates\":[1,2]}" + geometry_point: "{\"type\":\"Point\",\"coordinates\":[1,2]}" + geometry_line: "{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}" + geometry_poly: "{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}" + geometry_multipoint: "{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}" + geometry_multiline: "{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}" + geometry_multipoly: "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}" + geometry_collection: "{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}" } ) { geometry @@ -50,109 +50,58 @@ mod sqlite { geometry_collection } }"#), - @r###"{"data":{"createOneModel":{"geometry":"POINT(1 2)","geometry_point":"POINT(1 2)","geometry_line":"LINESTRING(1 2,3 4)","geometry_poly":"POLYGON((1 2,3 4,5 6,1 2))","geometry_multipoint":"MULTIPOINT(1 2)","geometry_multiline":"MULTILINESTRING((1 2,3 4))","geometry_multipoly":"MULTIPOLYGON(((1 2,3 4,5 6,1 2)))","geometry_collection":"GEOMETRYCOLLECTION(POINT(1 2))"}}}"### + @r###"{"data":{"createOneModel":{"geometry":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geometry_point":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geometry_line":"{\"type\": \"LineString\", \"coordinates\": [[1,2],[3,4]]}","geometry_poly":"{\"type\": \"Polygon\", \"coordinates\": [[[1,2],[3,4],[5,6],[1,2]]]}","geometry_multipoint":"{\"type\": \"MultiPoint\", \"coordinates\": [[1,2]]}","geometry_multiline":"{\"type\": \"MultiLineString\", \"coordinates\": [[[1,2],[3,4]]]}","geometry_multipoly":"{\"type\": \"MultiPolygon\", \"coordinates\": [[[[1,2],[3,4],[5,6],[1,2]]]]}","geometry_collection":"{\"type\": \"GeometryCollection\", \"geometries\": [{\"type\": \"Point\", \"coordinates\": [1,2]}]}"}}}"### ); Ok(()) } - fn schema_ewkt_geometry_srid() -> String { + fn schema_geometry_srid() -> String { let schema = indoc! { r#"model Model { - #id(id, String, @id, @default(cuid())) - geometry Geometry @test.Geometry(Geometry, 4326) - geometry_point Geometry @test.Geometry(Point, 4326) - geometry_line Geometry @test.Geometry(LineString, 4326) - geometry_poly Geometry @test.Geometry(Polygon, 4326) - geometry_multipoint Geometry @test.Geometry(MultiPoint, 4326) - geometry_multiline Geometry @test.Geometry(MultiLineString, 4326) - geometry_multipoly Geometry @test.Geometry(MultiPolygon, 4326) - geometry_collection Geometry @test.Geometry(GeometryCollection, 4326) - }"# + #id(id, String, @id, @default(cuid())) + geometry Geometry @test.Geometry(Geometry, 4326) + geometry_point Geometry @test.Geometry(Point, 4326) + geometry_line Geometry @test.Geometry(LineString, 4326) + geometry_poly Geometry @test.Geometry(Polygon, 4326) + geometry_multipoint Geometry @test.Geometry(MultiPoint, 4326) + geometry_multiline Geometry @test.Geometry(MultiLineString, 4326) + geometry_multipoly Geometry @test.Geometry(MultiPolygon, 4326) + geometry_collection Geometry @test.Geometry(GeometryCollection, 4326) + }"# }; schema.to_owned() } // "Spatialite common geometry types with srid" should "work" - #[connector_test(schema(schema_ewkt_geometry_srid))] + #[connector_test(schema(schema_geometry_srid))] async fn native_geometry_srid(runner: Runner) -> TestResult<()> { insta::assert_snapshot!( run_query!(&runner, r#"mutation { - createOneModel( - data: { - geometry: "SRID=4326;POINT(1 2)" - geometry_point: "SRID=4326;POINT(1 2)" - geometry_line: "SRID=4326;LINESTRING(1 2,3 4)" - geometry_poly: "SRID=4326;POLYGON((1 2,3 4,5 6,1 2))" - geometry_multipoint: "SRID=4326;MULTIPOINT(1 2)" - geometry_multiline: "SRID=4326;MULTILINESTRING((1 2,3 4))" - geometry_multipoly: "SRID=4326;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))" - geometry_collection: "SRID=4326;GEOMETRYCOLLECTION(POINT(1 2))" - } - ) { - geometry - geometry_point - geometry_line - geometry_poly - geometry_multipoint - geometry_multiline - geometry_multipoly - geometry_collection + createOneModel( + data: { + geometry: "{\"type\":\"Point\",\"coordinates\":[1,2]}" + geometry_point: "{\"type\":\"Point\",\"coordinates\":[1,2]}" + geometry_line: "{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}" + geometry_poly: "{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}" + geometry_multipoint: "{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}" + geometry_multiline: "{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}" + geometry_multipoly: "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}" + geometry_collection: "{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}" } - }"#), - @r###"{"data":{"createOneModel":{"geometry":"SRID=4326;POINT(1 2)","geometry_point":"SRID=4326;POINT(1 2)","geometry_line":"SRID=4326;LINESTRING(1 2,3 4)","geometry_poly":"SRID=4326;POLYGON((1 2,3 4,5 6,1 2))","geometry_multipoint":"SRID=4326;MULTIPOINT(1 2)","geometry_multiline":"SRID=4326;MULTILINESTRING((1 2,3 4))","geometry_multipoly":"SRID=4326;MULTIPOLYGON(((1 2,3 4,5 6,1 2)))","geometry_collection":"SRID=4326;GEOMETRYCOLLECTION(POINT(1 2))"}}}"### - ); - - Ok(()) - } - - fn schema_geojson_geometry() -> String { - let schema = indoc! { - r#"model Model { - #id(id, String, @id, @default(cuid())) - geometry GeoJson @test.Geometry(Geometry, 4326) - geometry_point GeoJson @test.Geometry(Point, 4326) - geometry_line GeoJson @test.Geometry(LineString, 4326) - geometry_poly GeoJson @test.Geometry(Polygon, 4326) - geometry_multipoint GeoJson @test.Geometry(MultiPoint, 4326) - geometry_multiline GeoJson @test.Geometry(MultiLineString, 4326) - geometry_multipoly GeoJson @test.Geometry(MultiPolygon, 4326) - geometry_collection GeoJson @test.Geometry(GeometryCollection, 4326) - }"# - }; - - schema.to_owned() - } - - // "Spatialite geometry types" should "work" with GeoJSON - #[connector_test(schema(schema_geojson_geometry))] - async fn native_geojson_geometry(runner: Runner) -> TestResult<()> { - insta::assert_snapshot!( - run_query!(&runner, r#"mutation { - createOneModel( - data: { - geometry: "{\"type\":\"Point\",\"coordinates\":[1,2]}" - geometry_point: "{\"type\":\"Point\",\"coordinates\":[1,2]}" - geometry_line: "{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}" - geometry_poly: "{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}" - geometry_multipoint: "{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}" - geometry_multiline: "{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}" - geometry_multipoly: "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}" - geometry_collection: "{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}" - } - ) { - geometry - geometry_point - geometry_line - geometry_poly - geometry_multipoint - geometry_multiline - geometry_multipoly - geometry_collection - } - }"#), - @r###"{"data":{"createOneModel":{"geometry":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geometry_point":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geometry_line":"{\"type\": \"LineString\", \"coordinates\": [[1,2],[3,4]]}","geometry_poly":"{\"type\": \"Polygon\", \"coordinates\": [[[1,2],[3,4],[5,6],[1,2]]]}","geometry_multipoint":"{\"type\": \"MultiPoint\", \"coordinates\": [[1,2]]}","geometry_multiline":"{\"type\": \"MultiLineString\", \"coordinates\": [[[1,2],[3,4]]]}","geometry_multipoly":"{\"type\": \"MultiPolygon\", \"coordinates\": [[[[1,2],[3,4],[5,6],[1,2]]]]}","geometry_collection":"{\"type\": \"GeometryCollection\", \"geometries\": [{\"type\": \"Point\", \"coordinates\": [1,2]}]}"}}}"### + ) { + geometry + geometry_point + geometry_line + geometry_poly + geometry_multipoint + geometry_multiline + geometry_multipoly + geometry_collection + } + }"#), + @r###"{"data":{"createOneModel":{"geometry":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geometry_point":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geometry_line":"{\"type\": \"LineString\", \"coordinates\": [[1,2],[3,4]]}","geometry_poly":"{\"type\": \"Polygon\", \"coordinates\": [[[1,2],[3,4],[5,6],[1,2]]]}","geometry_multipoint":"{\"type\": \"MultiPoint\", \"coordinates\": [[1,2]]}","geometry_multiline":"{\"type\": \"MultiLineString\", \"coordinates\": [[[1,2],[3,4]]]}","geometry_multipoly":"{\"type\": \"MultiPolygon\", \"coordinates\": [[[[1,2],[3,4],[5,6],[1,2]]]]}","geometry_collection":"{\"type\": \"GeometryCollection\", \"geometries\": [{\"type\": \"Point\", \"coordinates\": [1,2]}]}"}}}"### ); Ok(()) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs index 1ed76824b6fa..43d65ab3b9b3 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs @@ -425,7 +425,7 @@ mod mapped_create { } } -#[test_suite(capabilities(GeoJsonGeometry))] +#[test_suite(capabilities(Geometry))] mod geometry_create { use query_engine_tests::run_query; @@ -456,7 +456,7 @@ mod geometry_create { let schema = indoc! { r#"model TestModel { #id(id, Int, @id) - geometry GeoJson? + geometry Geometry? }"# }; @@ -468,7 +468,7 @@ mod geometry_create { r#"model TestModel { @@schema("test") #id(id, Int, @id) - geometry GeoJson? + geometry Geometry? }"# }; diff --git a/query-engine/connectors/mongodb-query-connector/src/value.rs b/query-engine/connectors/mongodb-query-connector/src/value.rs index 7c8a675818d9..cdea4e366990 100644 --- a/query-engine/connectors/mongodb-query-connector/src/value.rs +++ b/query-engine/connectors/mongodb-query-connector/src/value.rs @@ -9,8 +9,7 @@ use chrono::{TimeZone, Utc}; use itertools::Itertools; use psl::builtin_connectors::MongoDbType; use query_structure::{ - CompositeFieldRef, Field, GeometryFormat, PrismaValue, RelationFieldRef, ScalarFieldRef, SelectedField, - TypeIdentifier, + CompositeFieldRef, Field, PrismaValue, RelationFieldRef, ScalarFieldRef, SelectedField, TypeIdentifier, }; use serde_json::Value; use std::{convert::TryFrom, fmt::Display}; @@ -278,7 +277,7 @@ impl IntoBson for (&TypeIdentifier, PrismaValue) { } // Geometry - (TypeIdentifier::Geometry(GeometryFormat::GeoJSON), PrismaValue::GeoJson(json)) => { + (TypeIdentifier::Geometry, PrismaValue::GeoJson(json)) => { let val: Value = serde_json::from_str(&json)?; Bson::try_from(val).map_err(|_| MongoError::ConversionError { from: "Stringified GeoJSON".to_owned(), @@ -398,7 +397,8 @@ fn read_scalar_value(bson: Bson, meta: &ScalarOutputMeta) -> crate::Result PrismaValue::Json(serde_json::to_string(&bson.into_relaxed_extjson())?), // Geometry - (TypeIdentifier::Geometry(GeometryFormat::GeoJSON), bson @ Bson::Document(_)) => { + (TypeIdentifier::Geometry, bson @ Bson::Document(_)) => { + // TODO@geometry: should we do validation with crate geojson here instead ? PrismaValue::GeoJson(serde_json::to_string(&bson.into_relaxed_extjson())?) } diff --git a/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs b/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs index b6a3c59ee346..6bf4364826c0 100644 --- a/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs +++ b/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs @@ -1,5 +1,3 @@ -use std::str::FromStr; - use crate::context::Context; use chrono::Utc; use geozero::{geojson::GeoJson, ToWkt}; @@ -71,15 +69,6 @@ impl ScalarFieldExt for ScalarField { _ => unreachable!(), } } - (PrismaValue::Geometry(s), _) => { - // EWKT string should have been validated before - let geometry = GeometryValue::from_str(&s).unwrap(); - match self.type_family() { - TypeFamily::Geography(_) => Value::geography(geometry), - TypeFamily::Geometry(_) => Value::geometry(geometry), - _ => unreachable!(), - } - } (PrismaValue::Null, ident) => match ident { TypeIdentifier::String => Value::null_text(), TypeIdentifier::Float => Value::null_numeric(), @@ -101,7 +90,7 @@ impl ScalarFieldExt for ScalarField { TypeIdentifier::Int => Value::null_int32(), TypeIdentifier::BigInt => Value::null_int64(), TypeIdentifier::Bytes => Value::null_bytes(), - TypeIdentifier::Geometry(_) => Value::null_geometry(), + TypeIdentifier::Geometry => Value::null_geometry(), TypeIdentifier::Unsupported => unreachable!("No unsupported field should reach that path"), }, }; @@ -132,7 +121,7 @@ impl ScalarFieldExt for ScalarField { TypeIdentifier::Json => TypeFamily::Text(Some(TypeDataLength::Maximum)), TypeIdentifier::DateTime => TypeFamily::DateTime, TypeIdentifier::Bytes => TypeFamily::Text(parse_scalar_length(self)), - TypeIdentifier::Geometry(_) => { + TypeIdentifier::Geometry => { let type_info = self.native_type().map(|nt| { let name = nt.name(); let srid = match nt.args().as_slice() { @@ -170,7 +159,7 @@ pub fn convert_lossy<'a>(pv: PrismaValue) -> Value<'a> { PrismaValue::Bytes(b) => Value::bytes(b), // TODO@geom: Fix this when we know how to cast GeoJSON to an appropriate DB value PrismaValue::GeoJson(s) => Value::json(serde_json::from_str(&s).unwrap()), - PrismaValue::Geometry(s) => Value::geometry(GeometryValue::from_str(&s).unwrap()), + // PrismaValue::Geometry(s) => Value::geometry(GeometryValue::from_str(&s).unwrap()), PrismaValue::Null => Value::null_int32(), // Can't tell which type the null is supposed to be. PrismaValue::Object(_) => unimplemented!(), } diff --git a/query-engine/connectors/sql-query-connector/src/row.rs b/query-engine/connectors/sql-query-connector/src/row.rs index 36d3a3588c96..f19545db798a 100644 --- a/query-engine/connectors/sql-query-connector/src/row.rs +++ b/query-engine/connectors/sql-query-connector/src/row.rs @@ -5,7 +5,7 @@ use connector_interface::{coerce_null_to_zero_value, AggregationResult, Aggregat use geozero::wkt::WktStr; use geozero::ToJson; use quaint::{connector::ResultRow, Value, ValueType}; -use query_structure::{ConversionFailure, FieldArity, GeometryFormat, PrismaValue, Record, TypeIdentifier}; +use query_structure::{ConversionFailure, FieldArity, PrismaValue, Record, TypeIdentifier}; use std::{io, str::FromStr}; use uuid::Uuid; @@ -289,35 +289,25 @@ fn row_value_to_prisma_value(p_value: Value, meta: ColumnMetadata<'_>) -> Result ValueType::Bytes(Some(bytes)) => PrismaValue::Bytes(bytes.into()), _ => return Err(create_error(&p_value)), }, - TypeIdentifier::Geometry(GeometryFormat::EWKT) => match p_value.typed { + TypeIdentifier::Geometry => match p_value.typed { value if value.is_null() => PrismaValue::Null, - ValueType::Text(Some(ewkt)) => match ewkt.starts_with("SRID=0;") { - true => PrismaValue::Geometry(ewkt[7..].into()), - false => PrismaValue::Geometry(ewkt.into()), - }, - _ => return Err(create_error(&p_value)), - }, - TypeIdentifier::Geometry(GeometryFormat::GeoJSON) => match p_value.typed { - value if value.is_null() => PrismaValue::Null, - // MySQL @<=5.7 and MSSQL cannot return geometry as GeoJSON, so we must serialize - // the ewkt string back to geojson. However, per specification, GeoJSON geometries - // can only be represented with EPSG:4326 projection. Plus WKT can represent more - // spatial types than GeoJSON can, so this operation may fail. + // MSSQL 5.6 and SQL Server cannot return geometry as GeoJSON, so for consistency's + // sake Quaint will return EWKT for all vendors. We must then serialize the EWKT + // string back to geojson. WKT can represent more spatial types than GeoJSON, so + // this operation may fail. + // For now, we'll just discard the SRID, but ideally we should include it in the + // resulting GeoJSON, in case it is different than 4326 ValueType::Text(Some(ref ewkt)) => { - let wkt_start = if !ewkt.starts_with("SRID=") { - Ok(0) - } else if ewkt.starts_with("SRID=0;") { - Ok(7) - } else if ewkt.starts_with("SRID=4326;") { - Ok(10) + let wkt_start = if ewkt.starts_with("SRID=") { + ewkt.find(';').map(|i| i + 1).unwrap_or(0) } else { - Err(create_error(&p_value)) - }?; + 0 + }; WktStr(&ewkt[wkt_start..]) .to_json() .map(PrismaValue::GeoJson) .map_err(|_| create_error(&p_value))? - }, + } _ => return Err(create_error(&p_value)), }, TypeIdentifier::Unsupported => unreachable!("No unsupported field should reach that path"), diff --git a/query-engine/connectors/sql-query-connector/src/value.rs b/query-engine/connectors/sql-query-connector/src/value.rs index dabe3d71bfea..f1e7c63e1e72 100644 --- a/query-engine/connectors/sql-query-connector/src/value.rs +++ b/query-engine/connectors/sql-query-connector/src/value.rs @@ -100,7 +100,7 @@ pub fn to_prisma_value<'a, T: Into>>(qv: T) -> crate::Result s - .map(|s| PrismaValue::Geometry(s.to_string())) + .map(|s| PrismaValue::GeoJson(s.to_string())) .unwrap_or(PrismaValue::Null), }; diff --git a/query-engine/core/src/query_document/parser.rs b/query-engine/core/src/query_document/parser.rs index 4b93cf20b5b5..88be0f9b0e64 100644 --- a/query-engine/core/src/query_document/parser.rs +++ b/query-engine/core/src/query_document/parser.rs @@ -372,8 +372,7 @@ impl QueryDocumentParser { (PrismaValue::Bytes(bytes), ScalarType::Bytes) => Ok(PrismaValue::Bytes(bytes)), (PrismaValue::BigInt(b_int), ScalarType::BigInt) => Ok(PrismaValue::BigInt(b_int)), (PrismaValue::DateTime(s), ScalarType::DateTime) => Ok(PrismaValue::DateTime(s)), - (PrismaValue::GeoJson(s), ScalarType::GeoJson) => Ok(PrismaValue::GeoJson(s)), - (PrismaValue::Geometry(s), ScalarType::Geometry) => Ok(PrismaValue::Geometry(s)), + (PrismaValue::GeoJson(s), ScalarType::Geometry) => Ok(PrismaValue::GeoJson(s)), (PrismaValue::Null, ScalarType::Null) => Ok(PrismaValue::Null), // String coercion matchers @@ -389,17 +388,13 @@ impl QueryDocumentParser { (PrismaValue::String(s), ScalarType::Json) => Ok(PrismaValue::Json( self.parse_json(selection_path, argument_path, &s).map(|_| s)?, )), + (PrismaValue::Json(s) | PrismaValue::String(s), ScalarType::Geometry) => Ok(PrismaValue::GeoJson( + self.parse_geojson(selection_path, argument_path, &s).map(|_| s)?, + )), (PrismaValue::String(s), ScalarType::DateTime) => self .parse_datetime(selection_path, argument_path, s.as_str()) .map(PrismaValue::DateTime), - // WKT imput can hardly be validated, since all database vendors wkt dialect - // differ in subtle ways that make them incompatible. - (PrismaValue::String(s), ScalarType::Geometry) => Ok(PrismaValue::Geometry(s)), - (PrismaValue::Json(s) | PrismaValue::String(s), ScalarType::GeoJson) => Ok(PrismaValue::GeoJson( - self.parse_geojson(selection_path, argument_path, &s).map(|_| s)?, - )), - // Int coercion matchers (PrismaValue::Int(i), ScalarType::Int) => Ok(PrismaValue::Int(i)), (PrismaValue::Int(i), ScalarType::Float) => Ok(PrismaValue::Float(BigDecimal::from(i))), @@ -925,7 +920,6 @@ pub(crate) mod conversions { } PrismaValue::Json(_) => "JSON".to_string(), PrismaValue::GeoJson(_) => "GeoJSON".to_string(), - PrismaValue::Geometry(_) => "EWKTGeometry".to_string(), PrismaValue::Object(_) => "Object".to_string(), PrismaValue::Null => "Null".to_string(), PrismaValue::DateTime(_) => "DateTime".to_string(), diff --git a/query-engine/core/src/response_ir/internal.rs b/query-engine/core/src/response_ir/internal.rs index 8ca18fce16d1..4910ac4636a1 100644 --- a/query-engine/core/src/response_ir/internal.rs +++ b/query-engine/core/src/response_ir/internal.rs @@ -810,8 +810,7 @@ fn convert_prisma_value_graphql_protocol( (ScalarType::DateTime, PrismaValue::DateTime(dt)) => PrismaValue::DateTime(dt), (ScalarType::UUID, PrismaValue::Uuid(u)) => PrismaValue::Uuid(u), (ScalarType::Bytes, PrismaValue::Bytes(b)) => PrismaValue::Bytes(b), - (ScalarType::Geometry, PrismaValue::Geometry(s)) => PrismaValue::Geometry(s), - (ScalarType::GeoJson, PrismaValue::GeoJson(s)) => PrismaValue::GeoJson(s), + (ScalarType::Geometry, PrismaValue::GeoJson(s)) => PrismaValue::GeoJson(s), // The Decimal type doesn't have a corresponding PrismaValue variant. We need to serialize it // to String so that client can deserialize it as Decimal again. @@ -855,10 +854,7 @@ fn convert_prisma_value_json_protocol( (ScalarType::Bytes, PrismaValue::Bytes(x)) => { custom_types::make_object(custom_types::BYTES, PrismaValue::Bytes(x)) } - (ScalarType::Geometry, PrismaValue::Geometry(x)) => { - custom_types::make_object(custom_types::EWKT_GEOMETRY, PrismaValue::Geometry(x)) - } - (ScalarType::GeoJson, PrismaValue::GeoJson(x)) => { + (ScalarType::Geometry, PrismaValue::GeoJson(x)) => { custom_types::make_object(custom_types::GEOJSON, PrismaValue::GeoJson(x)) } diff --git a/query-engine/dmmf/src/ast_builders/datamodel_ast_builder.rs b/query-engine/dmmf/src/ast_builders/datamodel_ast_builder.rs index a1961d305f91..21977414db73 100644 --- a/query-engine/dmmf/src/ast_builders/datamodel_ast_builder.rs +++ b/query-engine/dmmf/src/ast_builders/datamodel_ast_builder.rs @@ -317,7 +317,6 @@ fn prisma_value_to_serde(value: &PrismaValue) -> serde_json::Value { PrismaValue::Uuid(val) => serde_json::Value::String(val.to_string()), PrismaValue::Json(val) => serde_json::Value::String(val.to_string()), PrismaValue::GeoJson(val) => serde_json::Value::String(val.to_string()), - PrismaValue::Geometry(val) => serde_json::Value::String(val.to_string()), PrismaValue::List(value_vec) => serde_json::Value::Array(value_vec.iter().map(prisma_value_to_serde).collect()), PrismaValue::Bytes(b) => serde_json::Value::String(encode_bytes(b)), PrismaValue::Object(pairs) => { diff --git a/query-engine/dmmf/src/ast_builders/schema_ast_builder/type_renderer.rs b/query-engine/dmmf/src/ast_builders/schema_ast_builder/type_renderer.rs index cc70a239a428..52ea13966e43 100644 --- a/query-engine/dmmf/src/ast_builders/schema_ast_builder/type_renderer.rs +++ b/query-engine/dmmf/src/ast_builders/schema_ast_builder/type_renderer.rs @@ -49,7 +49,6 @@ pub(super) fn render_output_type<'a>(output_type: &OutputType<'a>, ctx: &mut Ren ScalarType::UUID => "UUID", ScalarType::JsonList => "Json", ScalarType::Bytes => "Bytes", - ScalarType::GeoJson => "GeoJson", ScalarType::Geometry => "Geometry", }; diff --git a/query-engine/query-structure/src/field/mod.rs b/query-engine/query-structure/src/field/mod.rs index a6d137eb60d6..fc3e718dfde2 100644 --- a/query-engine/query-structure/src/field/mod.rs +++ b/query-engine/query-structure/src/field/mod.rs @@ -134,12 +134,6 @@ impl Field { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Copy)] -pub enum GeometryFormat { - EWKT, - GeoJSON, -} - #[derive(Clone, Debug, PartialEq, Eq, Hash, Copy)] #[allow(clippy::upper_case_acronyms)] pub enum TypeIdentifier { @@ -154,7 +148,7 @@ pub enum TypeIdentifier { Json, DateTime, Bytes, - Geometry(GeometryFormat), + Geometry, Unsupported, } @@ -182,8 +176,7 @@ impl TypeIdentifier { TypeIdentifier::Json => "Json".into(), TypeIdentifier::DateTime => "DateTime".into(), TypeIdentifier::Bytes => "Bytes".into(), - TypeIdentifier::Geometry(GeometryFormat::GeoJSON) => "GeoJson".into(), - TypeIdentifier::Geometry(GeometryFormat::EWKT) => "Geometry".into(), + TypeIdentifier::Geometry => "Geometry".into(), TypeIdentifier::Unsupported => "Unsupported".into(), } } @@ -262,8 +255,7 @@ impl From for TypeIdentifier { ScalarType::Json => Self::Json, ScalarType::Decimal => Self::Decimal, ScalarType::Bytes => Self::Bytes, - ScalarType::Geometry => Self::Geometry(GeometryFormat::EWKT), - ScalarType::GeoJson => Self::Geometry(GeometryFormat::GeoJSON), + ScalarType::Geometry => Self::Geometry, } } } diff --git a/query-engine/query-structure/src/field/scalar.rs b/query-engine/query-structure/src/field/scalar.rs index 5e6a0da680ab..0ab0ad322651 100644 --- a/query-engine/query-structure/src/field/scalar.rs +++ b/query-engine/query-structure/src/field/scalar.rs @@ -64,7 +64,7 @@ impl ScalarField { } pub fn is_geometry(&self) -> bool { - matches!(self.type_identifier(), TypeIdentifier::Geometry(_)) + matches!(self.type_identifier(), TypeIdentifier::Geometry) } pub fn container(&self) -> ParentContainer { diff --git a/query-engine/query-structure/src/prisma_value_ext.rs b/query-engine/query-structure/src/prisma_value_ext.rs index 4186844d8003..e4278b6c348a 100644 --- a/query-engine/query-structure/src/prisma_value_ext.rs +++ b/query-engine/query-structure/src/prisma_value_ext.rs @@ -1,5 +1,5 @@ use super::{PrismaValue, TypeIdentifier}; -use crate::{DomainError, GeometryFormat}; +use crate::DomainError; use bigdecimal::ToPrimitive; pub(crate) trait PrismaValueExtensions { @@ -23,8 +23,7 @@ impl PrismaValueExtensions for PrismaValue { (val @ PrismaValue::BigInt(_), TypeIdentifier::BigInt) => val, (val @ PrismaValue::Bytes(_), TypeIdentifier::Bytes) => val, (val @ PrismaValue::Json(_), TypeIdentifier::Json) => val, - (val @ PrismaValue::Geometry(_), TypeIdentifier::Geometry(GeometryFormat::EWKT)) => val, - (val @ PrismaValue::GeoJson(_), TypeIdentifier::Geometry(GeometryFormat::GeoJSON)) => val, + (val @ PrismaValue::GeoJson(_), TypeIdentifier::Geometry) => val, // Valid String coercions (PrismaValue::Int(i), TypeIdentifier::String) => PrismaValue::String(format!("{i}")), diff --git a/query-engine/request-handlers/src/protocols/graphql/schema_renderer/type_renderer.rs b/query-engine/request-handlers/src/protocols/graphql/schema_renderer/type_renderer.rs index 4d3b3e7b4471..97ab6bb9b954 100644 --- a/query-engine/request-handlers/src/protocols/graphql/schema_renderer/type_renderer.rs +++ b/query-engine/request-handlers/src/protocols/graphql/schema_renderer/type_renderer.rs @@ -47,7 +47,6 @@ impl<'a> GqlTypeRenderer<'a> { ScalarType::UUID => "UUID", ScalarType::JsonList => "Json", ScalarType::Bytes => "Bytes", - ScalarType::GeoJson => "GeoJson", ScalarType::Geometry => "Geometry", ScalarType::Null => unreachable!("Null types should not be picked for GQL rendering."), }; @@ -87,7 +86,6 @@ impl<'a> GqlTypeRenderer<'a> { ScalarType::UUID => "UUID", ScalarType::JsonList => "Json", ScalarType::Bytes => "Bytes", - ScalarType::GeoJson => "GeoJson", ScalarType::Geometry => "Geometry", ScalarType::Null => unreachable!("Null types should not be picked for GQL rendering."), }; diff --git a/query-engine/schema/src/build/input_types/fields/data_input_mapper/update.rs b/query-engine/schema/src/build/input_types/fields/data_input_mapper/update.rs index 4dee370e9a74..152dc3b9a0a7 100644 --- a/query-engine/schema/src/build/input_types/fields/data_input_mapper/update.rs +++ b/query-engine/schema/src/build/input_types/fields/data_input_mapper/update.rs @@ -40,7 +40,7 @@ impl DataInputFieldMapper for UpdateDataInputFieldMapper { } TypeIdentifier::Json => map_scalar_input_type_for_field(ctx, &sf), // TODO@geometry: Is this the right way ? - TypeIdentifier::Geometry(_) => map_scalar_input_type_for_field(ctx, &sf), + TypeIdentifier::Geometry => map_scalar_input_type_for_field(ctx, &sf), TypeIdentifier::DateTime => { InputType::object(update_operations_object_type(ctx, "DateTime", sf.clone(), false)) } diff --git a/query-engine/schema/src/build/input_types/fields/field_filter_types.rs b/query-engine/schema/src/build/input_types/fields/field_filter_types.rs index 54fd16aa1f53..154401d9b850 100644 --- a/query-engine/schema/src/build/input_types/fields/field_filter_types.rs +++ b/query-engine/schema/src/build/input_types/fields/field_filter_types.rs @@ -267,7 +267,7 @@ fn full_scalar_filter_type( // Inclusion filters are tricky because SQL Server doesn't allow direct equality check between geometries // so IN ( ... ) filters won't work either. The equality filters are hacked in Quaint, where they are // converted to .STEquals() expressions - TypeIdentifier::Geometry(_) => geometric_filters(ctx, mapped_scalar_type.clone()) + TypeIdentifier::Geometry => geometric_filters(ctx, mapped_scalar_type.clone()) .chain(equality_filters(mapped_scalar_type.clone(), nullable)) .collect(), diff --git a/query-engine/schema/src/build/input_types/mod.rs b/query-engine/schema/src/build/input_types/mod.rs index e7c8b099f24e..6b4684d66014 100644 --- a/query-engine/schema/src/build/input_types/mod.rs +++ b/query-engine/schema/src/build/input_types/mod.rs @@ -3,7 +3,7 @@ pub(crate) mod objects; use super::*; use fields::*; -use query_structure::{GeometryFormat, ScalarFieldRef}; +use query_structure::ScalarFieldRef; fn map_scalar_input_type_for_field<'a>(ctx: &'a QuerySchema, field: &ScalarFieldRef) -> InputType<'a> { map_scalar_input_type(ctx, field.type_identifier(), field.is_list()) @@ -19,8 +19,7 @@ fn map_scalar_input_type(ctx: &'_ QuerySchema, typ: TypeIdentifier, list: bool) TypeIdentifier::UUID => InputType::uuid(), TypeIdentifier::DateTime => InputType::date_time(), TypeIdentifier::Json => InputType::json(), - TypeIdentifier::Geometry(GeometryFormat::GeoJSON) => InputType::geojson_geometry(), - TypeIdentifier::Geometry(GeometryFormat::EWKT) => InputType::ewkt_geometry(), + TypeIdentifier::Geometry => InputType::geojson(), TypeIdentifier::Enum(id) => InputType::enum_type(map_schema_enum_type(ctx, id)), TypeIdentifier::Bytes => InputType::bytes(), TypeIdentifier::BigInt => InputType::bigint(), diff --git a/query-engine/schema/src/build/output_types/field.rs b/query-engine/schema/src/build/output_types/field.rs index 00d3a5d793f8..411e72896b60 100644 --- a/query-engine/schema/src/build/output_types/field.rs +++ b/query-engine/schema/src/build/output_types/field.rs @@ -1,6 +1,6 @@ use super::*; use input_types::fields::arguments; -use query_structure::{CompositeFieldRef, GeometryFormat, ScalarFieldRef}; +use query_structure::{CompositeFieldRef, ScalarFieldRef}; pub(crate) fn map_output_field(ctx: &'_ QuerySchema, model_field: ModelField) -> OutputField<'_> { let cloned_model_field = model_field.clone(); @@ -34,8 +34,7 @@ pub(crate) fn map_scalar_output_type<'a>(ctx: &'a QuerySchema, typ: &TypeIdentif TypeIdentifier::Boolean => OutputType::boolean(), TypeIdentifier::Enum(e) => OutputType::enum_type(map_schema_enum_type(ctx, *e)), TypeIdentifier::Json => OutputType::json(), - TypeIdentifier::Geometry(GeometryFormat::GeoJSON) => OutputType::geojson_geometry(), - TypeIdentifier::Geometry(GeometryFormat::EWKT) => OutputType::ewkt_geometry(), + TypeIdentifier::Geometry => OutputType::geojson(), TypeIdentifier::DateTime => OutputType::date_time(), TypeIdentifier::UUID => OutputType::uuid(), TypeIdentifier::Int => OutputType::int(), diff --git a/query-engine/schema/src/input_types.rs b/query-engine/schema/src/input_types.rs index bbde2b6475ca..7bbd48e1b18f 100644 --- a/query-engine/schema/src/input_types.rs +++ b/query-engine/schema/src/input_types.rs @@ -271,14 +271,10 @@ impl<'a> InputType<'a> { InputType::Scalar(ScalarType::Bytes) } - pub(crate) fn ewkt_geometry() -> InputType<'a> { + pub(crate) fn geojson() -> InputType<'a> { InputType::Scalar(ScalarType::Geometry) } - pub(crate) fn geojson_geometry() -> InputType<'a> { - InputType::Scalar(ScalarType::GeoJson) - } - pub(crate) fn null() -> InputType<'a> { InputType::Scalar(ScalarType::Null) } diff --git a/query-engine/schema/src/output_types.rs b/query-engine/schema/src/output_types.rs index aff460e7f55d..91589c986653 100644 --- a/query-engine/schema/src/output_types.rs +++ b/query-engine/schema/src/output_types.rs @@ -77,14 +77,10 @@ impl<'a> OutputType<'a> { InnerOutputType::Scalar(ScalarType::Bytes) } - pub(crate) fn ewkt_geometry() -> InnerOutputType<'a> { + pub(crate) fn geojson() -> InnerOutputType<'a> { InnerOutputType::Scalar(ScalarType::Geometry) } - pub(crate) fn geojson_geometry() -> InnerOutputType<'a> { - InnerOutputType::Scalar(ScalarType::GeoJson) - } - /// Attempts to recurse through the type until an object type is found. /// Returns Some(ObjectTypeStrongRef) if ab object type is found, None otherwise. pub fn as_object_type<'b>(&'b self) -> Option<&'b ObjectType<'a>> { diff --git a/query-engine/schema/src/query_schema.rs b/query-engine/schema/src/query_schema.rs index 14351b106c24..837c5a3e74c7 100644 --- a/query-engine/schema/src/query_schema.rs +++ b/query-engine/schema/src/query_schema.rs @@ -358,7 +358,6 @@ pub enum ScalarType { JsonList, UUID, Bytes, - GeoJson, Geometry, } @@ -377,7 +376,6 @@ impl fmt::Display for ScalarType { ScalarType::UUID => "UUID", ScalarType::JsonList => "Json", ScalarType::Bytes => "Bytes", - ScalarType::GeoJson => "GeoJson", ScalarType::Geometry => "Geometry", }; diff --git a/schema-engine/connectors/sql-schema-connector/src/sql_doc_parser.rs b/schema-engine/connectors/sql-schema-connector/src/sql_doc_parser.rs index ebdf6297ceef..f58e69522b6a 100644 --- a/schema-engine/connectors/sql-schema-connector/src/sql_doc_parser.rs +++ b/schema-engine/connectors/sql-schema-connector/src/sql_doc_parser.rs @@ -218,7 +218,7 @@ fn parse_typ_opt<'a>( ScalarType::Json => ColumnType::Json, ScalarType::Bytes => ColumnType::Bytes, ScalarType::Decimal => ColumnType::Numeric, - ScalarType::GeoJson | ScalarType::Geometry => ColumnType::Geometry, + ScalarType::Geometry => ColumnType::Geometry, }) .map(ParsedParamType::ColumnType) .or_else(|| { diff --git a/schema-engine/connectors/sql-schema-connector/src/sql_schema_calculator.rs b/schema-engine/connectors/sql-schema-connector/src/sql_schema_calculator.rs index c6404e0bb697..0c567da4d540 100644 --- a/schema-engine/connectors/sql-schema-connector/src/sql_schema_calculator.rs +++ b/schema-engine/connectors/sql-schema-connector/src/sql_schema_calculator.rs @@ -456,7 +456,6 @@ fn push_column_for_builtin_scalar_type( ScalarType::Decimal => sql::ColumnTypeFamily::Decimal, ScalarType::BigInt => sql::ColumnTypeFamily::BigInt, ScalarType::Geometry => sql::ColumnTypeFamily::Geometry, - ScalarType::GeoJson => sql::ColumnTypeFamily::Geometry, }; let native_type = field diff --git a/schema-engine/sql-schema-describer/tests/describers/postgres_describer_tests.rs b/schema-engine/sql-schema-describer/tests/describers/postgres_describer_tests.rs index d386104653ad..ffcff1ec4aaf 100644 --- a/schema-engine/sql-schema-describer/tests/describers/postgres_describer_tests.rs +++ b/schema-engine/sql-schema-describer/tests/describers/postgres_describer_tests.rs @@ -1173,7 +1173,7 @@ fn all_postgis_column_types_must_work(api: TestApi) { geography_collection GEOGRAPHY(GEOMETRYCOLLECTION, 9000), geography_collection_z GEOGRAPHY(GEOMETRYCOLLECTIONZ, 9000), geography_collection_m GEOGRAPHY(GEOMETRYCOLLECTIONM, 9000), - geography_collection_zm GEOGRAPHY(GEOMETRYCOLLECTIONZM, 9000), + geography_collection_zm GEOGRAPHY(GEOMETRYCOLLECTIONZM, 9000) ); "#; api.raw_cmd(sql); From 13d86243d699777f1d0daf9ffc9987357944bd6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Thu, 3 Oct 2024 21:22:37 +0200 Subject: [PATCH 054/103] Update sql-introspection-tests --- .../tests/native_types/postgres.rs | 67 ------------------- .../tests/native_types/sqlite.rs | 32 --------- 2 files changed, 99 deletions(-) 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 77cf8512bae0..eececda75f8a 100644 --- a/schema-engine/sql-introspection-tests/tests/native_types/postgres.rs +++ b/schema-engine/sql-introspection-tests/tests/native_types/postgres.rs @@ -39,72 +39,37 @@ const TYPES: &[(&str, &str)] = &[ const GEOMETRY_TYPES: &[(&str, &str)] = &[ ("geometry", "Geometry"), ("geometry_srid", "Geometry(Geometry, 3857)"), - ("geometry_geometry_m", "Geometry(GeometryM)"), ("geometry_geometry_z", "Geometry(GeometryZ)"), - ("geometry_geometry_zm", "Geometry(GeometryZM)"), ("geometry_point", "Geometry(Point)"), - ("geometry_point_m", "Geometry(PointM)"), ("geometry_point_z", "Geometry(PointZ)"), - ("geometry_point_zm", "Geometry(PointZM)"), ("geometry_linestring", "Geometry(LineString)"), - ("geometry_linestring_m", "Geometry(LineStringM)"), ("geometry_linestring_z", "Geometry(LineStringZ)"), - ("geometry_linestring_zm", "Geometry(LineStringZM)"), ("geometry_polygon", "Geometry(Polygon)"), - ("geometry_polygon_m", "Geometry(PolygonM)"), ("geometry_polygon_z", "Geometry(PolygonZ)"), - ("geometry_polygon_zm", "Geometry(PolygonZM)"), ("geometry_multipoint", "Geometry(MultiPoint)"), - ("geometry_multipoint_m", "Geometry(MultiPointM)"), ("geometry_multipoint_z", "Geometry(MultiPointZ)"), - ("geometry_multipoint_zm", "Geometry(MultiPointZM)"), ("geometry_multilinestring", "Geometry(MultiLineString)"), - ("geometry_multilinestring_m", "Geometry(MultiLineStringM)"), ("geometry_multilinestring_z", "Geometry(MultiLineStringZ)"), - ("geometry_multilinestring_zm", "Geometry(MultiLineStringZM)"), ("geometry_multipolygon", "Geometry(MultiPolygon)"), - ("geometry_multipolygon_m", "Geometry(MultiPolygonM)"), ("geometry_multipolygon_z", "Geometry(MultiPolygonZ)"), - ("geometry_multipolygon_zm", "Geometry(MultiPolygonZM)"), ("geometry_geometrycollection", "Geometry(GeometryCollection)"), - ("geometry_geometrycollection_m", "Geometry(GeometryCollectionM)"), ("geometry_geometrycollection_z", "Geometry(GeometryCollectionZ)"), - ("geometry_geometrycollection_zm", "Geometry(GeometryCollectionZM)"), ("geography_geometry", "Geography(Geometry, 4326)"), - ("geography_geometry_m", "Geography(GeometryM, 4326)"), ("geography_geometry_z", "Geography(GeometryZ, 4326)"), - ("geography_geometry_zm", "Geography(GeometryZM, 4326)"), ("geography_point", "Geography(Point, 4326)"), - ("geography_point_m", "Geography(PointM, 4326)"), ("geography_point_z", "Geography(PointZ, 4326)"), - ("geography_point_zm", "Geography(PointZM, 4326)"), ("geography_linestring", "Geography(LineString, 4326)"), - ("geography_linestring_m", "Geography(LineStringM, 4326)"), ("geography_linestring_z", "Geography(LineStringZ, 4326)"), - ("geography_linestring_zm", "Geography(LineStringZM, 4326)"), ("geography_polygon", "Geography(Polygon, 4326)"), - ("geography_polygon_m", "Geography(PolygonM, 4326)"), ("geography_polygon_z", "Geography(PolygonZ, 4326)"), - ("geography_polygon_zm", "Geography(PolygonZM, 4326)"), ("geography_multipoint", "Geography(MultiPoint, 4326)"), - ("geography_multipoint_m", "Geography(MultiPointM, 4326)"), ("geography_multipoint_z", "Geography(MultiPointZ, 4326)"), - ("geography_multipoint_zm", "Geography(MultiPointZM, 4326)"), ("geography_multilinestring", "Geography(MultiLineString, 4326)"), - ("geography_multilinestring_m", "Geography(MultiLineStringM, 4326)"), ("geography_multilinestring_z", "Geography(MultiLineStringZ, 4326)"), - ("geography_multilinestring_zm", "Geography(MultiLineStringZM, 4326)"), ("geography_multipolygon", "Geography(MultiPolygon, 4326)"), - ("geography_multipolygon_m", "Geography(MultiPolygonM, 4326)"), ("geography_multipolygon_z", "Geography(MultiPolygonZ, 4326)"), - ("geography_multipolygon_zm", "Geography(MultiPolygonZM, 4326)"), ("geography_geometrycollection", "Geography(GeometryCollection, 4326)"), - ("geography_geometrycollection_m", "Geography(GeometryCollectionM, 4326)"), ("geography_geometrycollection_z", "Geography(GeometryCollectionZ, 4326)"), - ( - "geography_geometrycollection_zm", - "Geography(GeometryCollectionZM, 4326)", - ), ]; #[test_connector(tags(Postgres), exclude(PostGIS, CockroachDb))] @@ -196,69 +161,37 @@ async fn native_type_spatial_columns_feature_on(api: &mut TestApi) -> TestResult id Int @id geometry Geometry geometry_srid Geometry @db.Geometry(Geometry, 3857) - geometry_geometry_m Geometry @db.Geometry(GeometryM) geometry_geometry_z Geometry @db.Geometry(GeometryZ) - geometry_geometry_zm Geometry @db.Geometry(GeometryZM) geometry_point Geometry @db.Geometry(Point) - geometry_point_m Geometry @db.Geometry(PointM) geometry_point_z Geometry @db.Geometry(PointZ) - geometry_point_zm Geometry @db.Geometry(PointZM) geometry_linestring Geometry @db.Geometry(LineString) - geometry_linestring_m Geometry @db.Geometry(LineStringM) geometry_linestring_z Geometry @db.Geometry(LineStringZ) - geometry_linestring_zm Geometry @db.Geometry(LineStringZM) geometry_polygon Geometry @db.Geometry(Polygon) - geometry_polygon_m Geometry @db.Geometry(PolygonM) geometry_polygon_z Geometry @db.Geometry(PolygonZ) - geometry_polygon_zm Geometry @db.Geometry(PolygonZM) geometry_multipoint Geometry @db.Geometry(MultiPoint) - geometry_multipoint_m Geometry @db.Geometry(MultiPointM) geometry_multipoint_z Geometry @db.Geometry(MultiPointZ) - geometry_multipoint_zm Geometry @db.Geometry(MultiPointZM) geometry_multilinestring Geometry @db.Geometry(MultiLineString) - geometry_multilinestring_m Geometry @db.Geometry(MultiLineStringM) geometry_multilinestring_z Geometry @db.Geometry(MultiLineStringZ) - geometry_multilinestring_zm Geometry @db.Geometry(MultiLineStringZM) geometry_multipolygon Geometry @db.Geometry(MultiPolygon) - geometry_multipolygon_m Geometry @db.Geometry(MultiPolygonM) geometry_multipolygon_z Geometry @db.Geometry(MultiPolygonZ) - geometry_multipolygon_zm Geometry @db.Geometry(MultiPolygonZM) geometry_geometrycollection Geometry @db.Geometry(GeometryCollection) - geometry_geometrycollection_m Geometry @db.Geometry(GeometryCollectionM) geometry_geometrycollection_z Geometry @db.Geometry(GeometryCollectionZ) - geometry_geometrycollection_zm Geometry @db.Geometry(GeometryCollectionZM) geography_geometry Geometry @db.Geography(Geometry, 4326) - geography_geometry_m Geometry @db.Geography(GeometryM, 4326) geography_geometry_z Geometry @db.Geography(GeometryZ, 4326) - geography_geometry_zm Geometry @db.Geography(GeometryZM, 4326) geography_point Geometry @db.Geography(Point, 4326) - geography_point_m Geometry @db.Geography(PointM, 4326) geography_point_z Geometry @db.Geography(PointZ, 4326) - geography_point_zm Geometry @db.Geography(PointZM, 4326) geography_linestring Geometry @db.Geography(LineString, 4326) - geography_linestring_m Geometry @db.Geography(LineStringM, 4326) geography_linestring_z Geometry @db.Geography(LineStringZ, 4326) - geography_linestring_zm Geometry @db.Geography(LineStringZM, 4326) geography_polygon Geometry @db.Geography(Polygon, 4326) - geography_polygon_m Geometry @db.Geography(PolygonM, 4326) geography_polygon_z Geometry @db.Geography(PolygonZ, 4326) - geography_polygon_zm Geometry @db.Geography(PolygonZM, 4326) geography_multipoint Geometry @db.Geography(MultiPoint, 4326) - geography_multipoint_m Geometry @db.Geography(MultiPointM, 4326) geography_multipoint_z Geometry @db.Geography(MultiPointZ, 4326) - geography_multipoint_zm Geometry @db.Geography(MultiPointZM, 4326) geography_multilinestring Geometry @db.Geography(MultiLineString, 4326) - geography_multilinestring_m Geometry @db.Geography(MultiLineStringM, 4326) geography_multilinestring_z Geometry @db.Geography(MultiLineStringZ, 4326) - geography_multilinestring_zm Geometry @db.Geography(MultiLineStringZM, 4326) geography_multipolygon Geometry @db.Geography(MultiPolygon, 4326) - geography_multipolygon_m Geometry @db.Geography(MultiPolygonM, 4326) geography_multipolygon_z Geometry @db.Geography(MultiPolygonZ, 4326) - geography_multipolygon_zm Geometry @db.Geography(MultiPolygonZM, 4326) geography_geometrycollection Geometry @db.Geography(GeometryCollection, 4326) - geography_geometrycollection_m Geometry @db.Geography(GeometryCollectionM, 4326) geography_geometrycollection_z Geometry @db.Geography(GeometryCollectionZ, 4326) - geography_geometrycollection_zm Geometry @db.Geography(GeometryCollectionZM, 4326) } "#} .to_string(); diff --git a/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs b/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs index 87c1cb0428e2..01c47b2802d7 100644 --- a/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs +++ b/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs @@ -11,36 +11,20 @@ async fn native_spatial_type_columns_feature_on(api: &mut TestApi) -> TestResult SELECT AddGeometryColumn('User', 'geometry_xy', 4326, 'GEOMETRY', 'XY', 0), AddGeometryColumn('User', 'geometry_xyz', 4326, 'GEOMETRY', 'XYZ', 0), - AddGeometryColumn('User', 'geometry_xym', 4326, 'GEOMETRY', 'XYM', 0), - AddGeometryColumn('User', 'geometry_xyzm', 4326, 'GEOMETRY', 'XYZM', 0), AddGeometryColumn('User', 'point_xy', 4326, 'POINT', 'XY', 0), AddGeometryColumn('User', 'point_xyz', 4326, 'POINT', 'XYZ', 0), - AddGeometryColumn('User', 'point_xym', 4326, 'POINT', 'XYM', 0), - AddGeometryColumn('User', 'point_xyzm', 4326, 'POINT', 'XYZM', 0), AddGeometryColumn('User', 'linestring_xy', 4326, 'LINESTRING', 'XY', 0), AddGeometryColumn('User', 'linestring_xyz', 4326, 'LINESTRING', 'XYZ', 0), - AddGeometryColumn('User', 'linestring_xym', 4326, 'LINESTRING', 'XYM', 0), - AddGeometryColumn('User', 'linestring_xyzm', 4326, 'LINESTRING', 'XYZM', 0), AddGeometryColumn('User', 'polygon_xy', 4326, 'POLYGON', 'XY', 0), AddGeometryColumn('User', 'polygon_xyz', 4326, 'POLYGON', 'XYZ', 0), - AddGeometryColumn('User', 'polygon_xym', 4326, 'POLYGON', 'XYM', 0), - AddGeometryColumn('User', 'polygon_xyzm', 4326, 'POLYGON', 'XYZM', 0), AddGeometryColumn('User', 'multipoint_xy', 4326, 'MULTIPOINT', 'XY', 0), AddGeometryColumn('User', 'multipoint_xyz', 4326, 'MULTIPOINT', 'XYZ', 0), - AddGeometryColumn('User', 'multipoint_xym', 4326, 'MULTIPOINT', 'XYM', 0), - AddGeometryColumn('User', 'multipoint_xyzm', 4326, 'MULTIPOINT', 'XYZM', 0), AddGeometryColumn('User', 'multilinestring_xy', 4326, 'MULTILINESTRING', 'XY', 0), AddGeometryColumn('User', 'multilinestring_xyz', 4326, 'MULTILINESTRING', 'XYZ', 0), - AddGeometryColumn('User', 'multilinestring_xym', 4326, 'MULTILINESTRING', 'XYM', 0), - AddGeometryColumn('User', 'multilinestring_xyzm', 4326, 'MULTILINESTRING', 'XYZM', 0), AddGeometryColumn('User', 'multipolygon_xy', 4326, 'MULTIPOLYGON', 'XY', 0), AddGeometryColumn('User', 'multipolygon_xyz', 4326, 'MULTIPOLYGON', 'XYZ', 0), - AddGeometryColumn('User', 'multipolygon_xym', 4326, 'MULTIPOLYGON', 'XYM', 0), - AddGeometryColumn('User', 'multipolygon_xyzm', 4326, 'MULTIPOLYGON', 'XYZM', 0), AddGeometryColumn('User', 'geometrycollection_xy', 4326, 'GEOMETRYCOLLECTION', 'XY', 0), AddGeometryColumn('User', 'geometrycollection_xyz', 4326, 'GEOMETRYCOLLECTION', 'XYZ', 0), - AddGeometryColumn('User', 'geometrycollection_xym', 4326, 'GEOMETRYCOLLECTION', 'XYM', 0), - AddGeometryColumn('User', 'geometrycollection_xyzm', 4326, 'GEOMETRYCOLLECTION', 'XYZM', 0); "#}; api.raw_cmd(setup).await; @@ -50,36 +34,20 @@ async fn native_spatial_type_columns_feature_on(api: &mut TestApi) -> TestResult id Int @id @default(autoincrement()) geometry_xy Geometry? @db.Geometry(Geometry, 4326) geometry_xyz Geometry? @db.Geometry(GeometryZ, 4326) - geometry_xym Geometry? @db.Geometry(GeometryM, 4326) - geometry_xyzm Geometry? @db.Geometry(GeometryZM, 4326) point_xy Geometry? @db.Geometry(Point, 4326) point_xyz Geometry? @db.Geometry(PointZ, 4326) - point_xym Geometry? @db.Geometry(PointM, 4326) - point_xyzm Geometry? @db.Geometry(PointZM, 4326) linestring_xy Geometry? @db.Geometry(LineString, 4326) linestring_xyz Geometry? @db.Geometry(LineStringZ, 4326) - linestring_xym Geometry? @db.Geometry(LineStringM, 4326) - linestring_xyzm Geometry? @db.Geometry(LineStringZM, 4326) polygon_xy Geometry? @db.Geometry(Polygon, 4326) polygon_xyz Geometry? @db.Geometry(PolygonZ, 4326) - polygon_xym Geometry? @db.Geometry(PolygonM, 4326) - polygon_xyzm Geometry? @db.Geometry(PolygonZM, 4326) multipoint_xy Geometry? @db.Geometry(MultiPoint, 4326) multipoint_xyz Geometry? @db.Geometry(MultiPointZ, 4326) - multipoint_xym Geometry? @db.Geometry(MultiPointM, 4326) - multipoint_xyzm Geometry? @db.Geometry(MultiPointZM, 4326) multilinestring_xy Geometry? @db.Geometry(MultiLineString, 4326) multilinestring_xyz Geometry? @db.Geometry(MultiLineStringZ, 4326) - multilinestring_xym Geometry? @db.Geometry(MultiLineStringM, 4326) - multilinestring_xyzm Geometry? @db.Geometry(MultiLineStringZM, 4326) multipolygon_xy Geometry? @db.Geometry(MultiPolygon, 4326) multipolygon_xyz Geometry? @db.Geometry(MultiPolygonZ, 4326) - multipolygon_xym Geometry? @db.Geometry(MultiPolygonM, 4326) - multipolygon_xyzm Geometry? @db.Geometry(MultiPolygonZM, 4326) geometrycollection_xy Geometry? @db.Geometry(GeometryCollection, 4326) geometrycollection_xyz Geometry? @db.Geometry(GeometryCollectionZ, 4326) - geometrycollection_xym Geometry? @db.Geometry(GeometryCollectionM, 4326) - geometrycollection_xyzm Geometry? @db.Geometry(GeometryCollectionZM, 4326) } "#]]; From 73f051a07b8a0c8628119176e3d7b4c32a8a6d15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Thu, 3 Oct 2024 22:52:37 +0200 Subject: [PATCH 055/103] Fix srid handling for sql server --- quaint/src/ast/function/geom_from_text.rs | 6 +++--- quaint/src/ast/values.rs | 16 ++++++++-------- quaint/src/connector/mysql/native/conversion.rs | 2 +- quaint/src/visitor/mssql.rs | 11 +++++++---- quaint/src/visitor/mysql.rs | 10 ++++++---- quaint/src/visitor/postgres.rs | 10 ++++++---- quaint/src/visitor/sqlite.rs | 10 ++++++---- .../src/model_extensions/scalar_field.rs | 10 ++-------- 8 files changed, 39 insertions(+), 36 deletions(-) diff --git a/quaint/src/ast/function/geom_from_text.rs b/quaint/src/ast/function/geom_from_text.rs index a8b4481f9236..fcbfc59eec5b 100644 --- a/quaint/src/ast/function/geom_from_text.rs +++ b/quaint/src/ast/function/geom_from_text.rs @@ -5,7 +5,7 @@ use crate::ast::Expression; #[derive(Debug, Clone, PartialEq)] pub struct GeomFromText<'a> { pub(crate) wkt_expression: Box>, - pub(crate) srid_expression: Box>, + pub(crate) srid_expression: Option>>, pub(crate) geography: bool, } @@ -26,14 +26,14 @@ pub struct GeomFromText<'a> { /// # Ok(()) /// # } /// ``` -pub fn geom_from_text<'a, G, S>(wkt_expression: G, srid_expression: S, geography: bool) -> Function<'a> +pub fn geom_from_text<'a, G, S>(wkt_expression: G, srid_expression: Option, geography: bool) -> Function<'a> where G: Into>, S: Into>, { let fun = GeomFromText { wkt_expression: Box::new(wkt_expression.into()), - srid_expression: Box::new(srid_expression.into()), + srid_expression: srid_expression.map(|s| Box::new(s.into())), geography, }; diff --git a/quaint/src/ast/values.rs b/quaint/src/ast/values.rs index fc9d08355344..e3226adfd6ac 100644 --- a/quaint/src/ast/values.rs +++ b/quaint/src/ast/values.rs @@ -40,14 +40,14 @@ where #[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] pub struct GeometryValue { pub wkt: String, - pub srid: i32, + pub srid: Option, } impl Display for GeometryValue { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self.srid { - 0 => (), - srid => write!(f, "SRID={};", srid)?, + None | Some(0) => (), + Some(srid) => write!(f, "SRID={};", srid)?, } f.write_str(&self.wkt) } @@ -61,11 +61,11 @@ impl FromStr for GeometryValue { EWKT_REGEX .captures(s) .map(|capture| { - let srid = match capture.name("srid").map(|v| v.as_str().parse::()) { - None => Ok(0), - Some(Ok(srid)) => Ok(srid), - Some(Err(_)) => Err(Error::builder(ErrorKind::conversion("Invalid EWKT SRID")).build()), - }?; + let srid = capture + .name("srid") + .map(|v| v.as_str().parse::()) + .transpose() + .map_err(|_| Error::builder(ErrorKind::conversion("Invalid EWKT SRID")).build())?; let wkt = capture.name("geometry").map(|v| v.as_str()).unwrap().to_string(); Ok(GeometryValue { srid, wkt }) }) diff --git a/quaint/src/connector/mysql/native/conversion.rs b/quaint/src/connector/mysql/native/conversion.rs index 7a57ea6908c0..a05cdabf8dc4 100644 --- a/quaint/src/connector/mysql/native/conversion.rs +++ b/quaint/src/connector/mysql/native/conversion.rs @@ -72,7 +72,7 @@ pub fn conv_params(params: &[Value<'_>]) -> crate::Result { ValueType::Geometry(g) | ValueType::Geography(g) => match g { None => None, Some(ref g) => { - let res = WktStr(&g.wkt).to_mysql_wkb(Some(g.srid)).map(my::Value::Bytes); + let res = WktStr(&g.wkt).to_mysql_wkb(g.srid).map(my::Value::Bytes); if res.is_err() { let msg = "Couldn't convert value `{g}` into EWKB."; diff --git a/quaint/src/visitor/mssql.rs b/quaint/src/visitor/mssql.rs index a9f700e5ea2b..15b5ae0324b7 100644 --- a/quaint/src/visitor/mssql.rs +++ b/quaint/src/visitor/mssql.rs @@ -424,10 +424,10 @@ impl<'a> Visitor<'a> for Mssql<'a> { // TODO@geometry: find a way to avoid cloning ValueType::Geometry(g) => g .as_ref() - .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.raw(), false))), + .map(|g| self.visit_function(geom_from_text(g.wkt.clone(), g.srid, false))), ValueType::Geography(g) => g .as_ref() - .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.raw(), true))), + .map(|g| self.visit_function(geom_from_text(g.wkt.clone(), g.srid, true))), }; match res { @@ -839,8 +839,11 @@ impl<'a> Visitor<'a> for Mssql<'a> { self.write(if geom.geography { "geography" } else { "geometry" })?; self.surround_with("::STGeomFromText(", ")", |ref mut s| { s.visit_expression(*geom.wkt_expression)?; - s.write(",")?; - s.visit_expression(*geom.srid_expression)?; + if geom.geography { + s.visit_expression(*geom.srid_expression.unwrap_or_else(|| Box::new(4326.into())))?; + } else { + s.visit_expression(*geom.srid_expression.unwrap_or_else(|| Box::new(0.into())))?; + } Ok(()) }) } diff --git a/quaint/src/visitor/mysql.rs b/quaint/src/visitor/mysql.rs index 47a7b7b8d6c7..dd3c67720b39 100644 --- a/quaint/src/visitor/mysql.rs +++ b/quaint/src/visitor/mysql.rs @@ -196,10 +196,10 @@ impl<'a> Visitor<'a> for Mysql<'a> { // TODO@geometry: find a way to avoid cloning ValueType::Geometry(g) => g .as_ref() - .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.raw(), false))), + .map(|g| self.visit_function(geom_from_text(g.wkt.clone(), g.srid, false))), ValueType::Geography(g) => g .as_ref() - .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.raw(), true))), + .map(|g| self.visit_function(geom_from_text(g.wkt.clone(), g.srid, true))), }; match res { @@ -728,8 +728,10 @@ impl<'a> Visitor<'a> for Mysql<'a> { fn visit_geom_from_text(&mut self, geom: GeomFromText<'a>) -> visitor::Result { self.surround_with("ST_GeomFromText(", ")", |ref mut s| { s.visit_expression(*geom.wkt_expression)?; - s.write(",")?; - s.visit_expression(*geom.srid_expression)?; + if let Some(srid_expression) = geom.srid_expression { + s.write(",")?; + s.visit_expression(*srid_expression)?; + } Ok(()) }) } diff --git a/quaint/src/visitor/postgres.rs b/quaint/src/visitor/postgres.rs index b6a40b97a015..c0ff38666338 100644 --- a/quaint/src/visitor/postgres.rs +++ b/quaint/src/visitor/postgres.rs @@ -260,10 +260,10 @@ impl<'a> Visitor<'a> for Postgres<'a> { // TODO@geometry: find a way to avoid cloning ValueType::Geometry(g) => g .as_ref() - .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.raw(), false))), + .map(|g| self.visit_function(geom_from_text(g.wkt.clone(), g.srid, false))), ValueType::Geography(g) => g .as_ref() - .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.raw(), true))), + .map(|g| self.visit_function(geom_from_text(g.wkt.clone(), g.srid, true))), }; match res { @@ -792,8 +792,10 @@ impl<'a> Visitor<'a> for Postgres<'a> { fn visit_geom_from_text(&mut self, geom: GeomFromText<'a>) -> visitor::Result { self.surround_with("ST_GeomFromText(", ")", |ref mut s| { s.visit_expression(*geom.wkt_expression)?; - s.write(",")?; - s.visit_expression(*geom.srid_expression)?; + if let Some(srid_expression) = geom.srid_expression { + s.write(",")?; + s.visit_expression(*srid_expression)?; + } Ok(()) }) } diff --git a/quaint/src/visitor/sqlite.rs b/quaint/src/visitor/sqlite.rs index c50aaccdc0a6..c20d6fd9f0b2 100644 --- a/quaint/src/visitor/sqlite.rs +++ b/quaint/src/visitor/sqlite.rs @@ -143,10 +143,10 @@ impl<'a> Visitor<'a> for Sqlite<'a> { // TODO@geometry: find a way to avoid cloning ValueType::Geometry(g) => g .as_ref() - .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.raw(), false))), + .map(|g| self.visit_function(geom_from_text(g.wkt.clone(), g.srid, false))), ValueType::Geography(g) => g .as_ref() - .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.raw(), true))), + .map(|g| self.visit_function(geom_from_text(g.wkt.clone(), g.srid, true))), }; match res { @@ -502,8 +502,10 @@ impl<'a> Visitor<'a> for Sqlite<'a> { fn visit_geom_from_text(&mut self, geom: GeomFromText<'a>) -> visitor::Result { self.surround_with("ST_GeomFromText(", ")", |ref mut s| { s.visit_expression(*geom.wkt_expression)?; - s.write(",")?; - s.visit_expression(*geom.srid_expression)?; + if let Some(srid_expression) = geom.srid_expression { + s.write(",")?; + s.visit_expression(*srid_expression)?; + } Ok(()) }) } diff --git a/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs b/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs index 6bf4364826c0..ad186b602e39 100644 --- a/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs +++ b/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs @@ -58,14 +58,8 @@ impl ScalarFieldExt for ScalarField { // GeoJSON string should have been validated before let wkt = GeoJson(&s).to_wkt().unwrap(); match self.type_family() { - TypeFamily::Geography(srid) => Value::geography(GeometryValue { - wkt, - srid: srid.unwrap_or(0), - }), - TypeFamily::Geometry(srid) => Value::geometry(GeometryValue { - wkt, - srid: srid.unwrap_or(0), - }), + TypeFamily::Geography(srid) => Value::geography(GeometryValue { wkt, srid }), + TypeFamily::Geometry(srid) => Value::geometry(GeometryValue { wkt, srid }), _ => unreachable!(), } } From 7c834a76c950f5ccf0f417254e8ea32094ec8242 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Thu, 3 Oct 2024 22:59:01 +0200 Subject: [PATCH 056/103] Fix spatialite introspection test --- .../sql-introspection-tests/tests/native_types/sqlite.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs b/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs index 01c47b2802d7..945c27951b3a 100644 --- a/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs +++ b/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs @@ -24,7 +24,7 @@ async fn native_spatial_type_columns_feature_on(api: &mut TestApi) -> TestResult AddGeometryColumn('User', 'multipolygon_xy', 4326, 'MULTIPOLYGON', 'XY', 0), AddGeometryColumn('User', 'multipolygon_xyz', 4326, 'MULTIPOLYGON', 'XYZ', 0), AddGeometryColumn('User', 'geometrycollection_xy', 4326, 'GEOMETRYCOLLECTION', 'XY', 0), - AddGeometryColumn('User', 'geometrycollection_xyz', 4326, 'GEOMETRYCOLLECTION', 'XYZ', 0), + AddGeometryColumn('User', 'geometrycollection_xyz', 4326, 'GEOMETRYCOLLECTION', 'XYZ', 0); "#}; api.raw_cmd(setup).await; From 41b829ccc7bd0bcaeff782a56fb793ef38feb2ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Thu, 3 Oct 2024 23:43:28 +0200 Subject: [PATCH 057/103] Fix spatialite migration tests --- .../src/sql_renderer/sqlite_renderer.rs | 2 +- .../tests/migrations/diff.rs | 36 +++++++++++++------ 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/schema-engine/connectors/sql-schema-connector/src/sql_renderer/sqlite_renderer.rs b/schema-engine/connectors/sql-schema-connector/src/sql_renderer/sqlite_renderer.rs index 3119b3cc8473..c62bc1a9cb02 100644 --- a/schema-engine/connectors/sql-schema-connector/src/sql_renderer/sqlite_renderer.rs +++ b/schema-engine/connectors/sql-schema-connector/src/sql_renderer/sqlite_renderer.rs @@ -150,7 +150,7 @@ impl SqlRenderer for SqliteFlavour { if create_geometries.is_empty() { create_table.to_string() } else { - create_table.to_string() + "\n;" + &create_geometries + create_table.to_string() + ";\n" + &create_geometries } } diff --git a/schema-engine/sql-migration-tests/tests/migrations/diff.rs b/schema-engine/sql-migration-tests/tests/migrations/diff.rs index 57da31f7e1c7..907f9dcc3770 100644 --- a/schema-engine/sql-migration-tests/tests/migrations/diff.rs +++ b/schema-engine/sql-migration-tests/tests/migrations/diff.rs @@ -822,11 +822,19 @@ fn from_multi_file_schema_datasource_to_url(mut api: TestApi) { api.diff(input).unwrap(); - let expected_printed_messages = expect![[r#" - [ - "-- DropTable\nPRAGMA foreign_keys=off;\nDROP TABLE \"cows\";\nPRAGMA foreign_keys=on;\n\n-- CreateTable\nCREATE TABLE \"cats\" (\n \"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n \"meows\" BOOLEAN DEFAULT true\n);\n", - ] - "#]]; + let expected_printed_messages = if api.tags().contains(test_setup::Tags::Spatialite) { + expect![[r#" + [ + "-- DropTable\nPRAGMA foreign_keys=off;\nSELECT DropTable(NULL, 'cows');\nPRAGMA foreign_keys=on;\n\n-- CreateTable\nCREATE TABLE \"cats\" (\n \"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n \"meows\" BOOLEAN DEFAULT true\n);\n", + ] + "#]] + } else { + expect![[r#" + [ + "-- DropTable\nPRAGMA foreign_keys=off;\nDROP TABLE \"cows\";\nPRAGMA foreign_keys=on;\n\n-- CreateTable\nCREATE TABLE \"cats\" (\n \"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n \"meows\" BOOLEAN DEFAULT true\n);\n", + ] + "#]] + }; expected_printed_messages.assert_debug_eq(&host.printed_messages.lock().unwrap()); } @@ -888,11 +896,19 @@ fn from_multi_file_schema_datamodel_to_url(mut api: TestApi) { api.diff(input).unwrap(); - let expected_printed_messages = expect![[r#" - [ - "-- DropTable\nPRAGMA foreign_keys=off;\nDROP TABLE \"cows\";\nPRAGMA foreign_keys=on;\n\n-- DropTable\nPRAGMA foreign_keys=off;\nDROP TABLE \"dogs\";\nPRAGMA foreign_keys=on;\n\n-- CreateTable\nCREATE TABLE \"cats\" (\n \"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n \"meows\" BOOLEAN DEFAULT true\n);\n", - ] - "#]]; + let expected_printed_messages = if api.tags().contains(test_setup::Tags::Spatialite) { + expect![[r#" + [ + "-- DropTable\nPRAGMA foreign_keys=off;\nSELECT DropTable(NULL, 'cows');\nPRAGMA foreign_keys=on;\n\n-- DropTable\nPRAGMA foreign_keys=off;\nSELECT DropTable(NULL, 'dogs');\nPRAGMA foreign_keys=on;\n\n-- CreateTable\nCREATE TABLE \"cats\" (\n \"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n \"meows\" BOOLEAN DEFAULT true\n);\n", + ] + "#]] + } else { + expect![[r#" + [ + "-- DropTable\nPRAGMA foreign_keys=off;\nDROP TABLE \"cows\";\nPRAGMA foreign_keys=on;\n\n-- DropTable\nPRAGMA foreign_keys=off;\nDROP TABLE \"dogs\";\nPRAGMA foreign_keys=on;\n\n-- CreateTable\nCREATE TABLE \"cats\" (\n \"id\" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,\n \"meows\" BOOLEAN DEFAULT true\n);\n", + ] + "#]] + }; expected_printed_messages.assert_debug_eq(&host.printed_messages.lock().unwrap()); } From c08999d387f897aa11cb48b1f95df2bf1cd22ab3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Fri, 4 Oct 2024 00:06:01 +0200 Subject: [PATCH 058/103] Fix more tests --- .../tests/native_types/sqlite.rs | 34 ++-- .../cockroach_describer_tests.rs | 192 ++---------------- 2 files changed, 33 insertions(+), 193 deletions(-) diff --git a/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs b/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs index 945c27951b3a..1b759f4f232b 100644 --- a/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs +++ b/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs @@ -31,23 +31,23 @@ async fn native_spatial_type_columns_feature_on(api: &mut TestApi) -> TestResult let expectation = expect![[r#" model User { - id Int @id @default(autoincrement()) - geometry_xy Geometry? @db.Geometry(Geometry, 4326) - geometry_xyz Geometry? @db.Geometry(GeometryZ, 4326) - point_xy Geometry? @db.Geometry(Point, 4326) - point_xyz Geometry? @db.Geometry(PointZ, 4326) - linestring_xy Geometry? @db.Geometry(LineString, 4326) - linestring_xyz Geometry? @db.Geometry(LineStringZ, 4326) - polygon_xy Geometry? @db.Geometry(Polygon, 4326) - polygon_xyz Geometry? @db.Geometry(PolygonZ, 4326) - multipoint_xy Geometry? @db.Geometry(MultiPoint, 4326) - multipoint_xyz Geometry? @db.Geometry(MultiPointZ, 4326) - multilinestring_xy Geometry? @db.Geometry(MultiLineString, 4326) - multilinestring_xyz Geometry? @db.Geometry(MultiLineStringZ, 4326) - multipolygon_xy Geometry? @db.Geometry(MultiPolygon, 4326) - multipolygon_xyz Geometry? @db.Geometry(MultiPolygonZ, 4326) - geometrycollection_xy Geometry? @db.Geometry(GeometryCollection, 4326) - geometrycollection_xyz Geometry? @db.Geometry(GeometryCollectionZ, 4326) + id Int @id @default(autoincrement()) + geometry_xy Geometry? @db.Geometry(Geometry, 4326) + geometry_xyz Geometry? @db.Geometry(GeometryZ, 4326) + point_xy Geometry? @db.Geometry(Point, 4326) + point_xyz Geometry? @db.Geometry(PointZ, 4326) + linestring_xy Geometry? @db.Geometry(LineString, 4326) + linestring_xyz Geometry? @db.Geometry(LineStringZ, 4326) + polygon_xy Geometry? @db.Geometry(Polygon, 4326) + polygon_xyz Geometry? @db.Geometry(PolygonZ, 4326) + multipoint_xy Geometry? @db.Geometry(MultiPoint, 4326) + multipoint_xyz Geometry? @db.Geometry(MultiPointZ, 4326) + multilinestring_xy Geometry? @db.Geometry(MultiLineString, 4326) + multilinestring_xyz Geometry? @db.Geometry(MultiLineStringZ, 4326) + multipolygon_xy Geometry? @db.Geometry(MultiPolygon, 4326) + multipolygon_xyz Geometry? @db.Geometry(MultiPolygonZ, 4326) + geometrycollection_xy Geometry? @db.Geometry(GeometryCollection, 4326) + geometrycollection_xyz Geometry? @db.Geometry(GeometryCollectionZ, 4326) } "#]]; 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 f87fa67aaf09..2ae2026f5718 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 @@ -215,69 +215,37 @@ fn all_postgis_column_types_must_work(api: TestApi) { let migration = r#" CREATE TABLE "Spatial" ( geometry_geometry GEOMETRY(GEOMETRY, 3857), - geometry_geometry_m GEOMETRY(GEOMETRYZ, 3857), - geometry_geometry_z GEOMETRY(GEOMETRYM, 3857), - geometry_geometry_zm GEOMETRY(GEOMETRYZM, 3857), + geometry_geometry_z GEOMETRY(GEOMETRYZ, 3857), geometry_point GEOMETRY(POINT, 3857), - geometry_point_m GEOMETRY(POINTZ, 3857), - geometry_point_z GEOMETRY(POINTM, 3857), - geometry_point_zm GEOMETRY(POINTZM, 3857), + geometry_point_z GEOMETRY(POINTZ, 3857), geometry_line GEOMETRY(LINESTRING, 3857), - geometry_line_m GEOMETRY(LINESTRINGZ, 3857), - geometry_line_z GEOMETRY(LINESTRINGM, 3857), - geometry_line_zm GEOMETRY(LINESTRINGZM, 3857), + geometry_line_z GEOMETRY(LINESTRINGZ, 3857), geometry_polygon GEOMETRY(POLYGON, 3857), - geometry_polygon_m GEOMETRY(POLYGONZ, 3857), - geometry_polygon_z GEOMETRY(POLYGONM, 3857), - geometry_polygon_zm GEOMETRY(POLYGONZM, 3857), + geometry_polygon_z GEOMETRY(POLYGONZ, 3857), geometry_multipoint GEOMETRY(MULTIPOINT, 3857), - geometry_multipoint_m GEOMETRY(MULTIPOINTZ, 3857), - geometry_multipoint_z GEOMETRY(MULTIPOINTM, 3857), - geometry_multipoint_zm GEOMETRY(MULTIPOINTZM, 3857), + geometry_multipoint_z GEOMETRY(MULTIPOINTZ, 3857), geometry_multiline GEOMETRY(MULTILINESTRING, 3857), - geometry_multiline_m GEOMETRY(MULTILINESTRINGZ, 3857), - geometry_multiline_z GEOMETRY(MULTILINESTRINGM, 3857), - geometry_multiline_zm GEOMETRY(MULTILINESTRINGZM, 3857), + geometry_multiline_z GEOMETRY(MULTILINESTRINGZ, 3857), geometry_multipolygon GEOMETRY(MULTIPOLYGON, 3857), - geometry_multipolygon_m GEOMETRY(MULTIPOLYGONZ, 3857), - geometry_multipolygon_z GEOMETRY(MULTIPOLYGONM, 3857), - geometry_multipolygon_zm GEOMETRY(MULTIPOLYGONZM, 3857), + geometry_multipolygon_z GEOMETRY(MULTIPOLYGONZ, 3857), geometry_collection GEOMETRY(GEOMETRYCOLLECTION, 3857), - geometry_collection_m GEOMETRY(GEOMETRYCOLLECTIONZ, 3857), - geometry_collection_z GEOMETRY(GEOMETRYCOLLECTIONM, 3857), - geometry_collection_zm GEOMETRY(GEOMETRYCOLLECTIONZM, 3857), + geometry_collection_z GEOMETRY(GEOMETRYCOLLECTIONZ, 3857), geography_geometry GEOGRAPHY(GEOMETRY, 9000), - geography_geometry_m GEOGRAPHY(GEOMETRYZ, 9000), - geography_geometry_z GEOGRAPHY(GEOMETRYM, 9000), - geography_geometry_zm GEOGRAPHY(GEOMETRYZM, 9000), + geography_geometry_z GEOGRAPHY(GEOMETRYZ, 9000), geography_point GEOGRAPHY(POINT, 9000), - geography_point_m GEOGRAPHY(POINTZ, 9000), - geography_point_z GEOGRAPHY(POINTM, 9000), - geography_point_zm GEOGRAPHY(POINTZM, 9000), + geography_point_z GEOGRAPHY(POINTZ, 9000), geography_line GEOGRAPHY(LINESTRING, 9000), - geography_line_m GEOGRAPHY(LINESTRINGZ, 9000), - geography_line_z GEOGRAPHY(LINESTRINGM, 9000), - geography_line_zm GEOGRAPHY(LINESTRINGZM, 9000), + geography_line_z GEOGRAPHY(LINESTRINGZ, 9000), geography_polygon GEOGRAPHY(POLYGON, 9000), - geography_polygon_m GEOGRAPHY(POLYGONZ, 9000), - geography_polygon_z GEOGRAPHY(POLYGONM, 9000), - geography_polygon_zm GEOGRAPHY(POLYGONZM, 9000), + geography_polygon_z GEOGRAPHY(POLYGONZ, 9000), geography_multipoint GEOGRAPHY(MULTIPOINT, 9000), - geography_multipoint_m GEOGRAPHY(MULTIPOINTZ, 9000), - geography_multipoint_z GEOGRAPHY(MULTIPOINTM, 9000), - geography_multipoint_zm GEOGRAPHY(MULTIPOINTZM, 9000), + geography_multipoint_z GEOGRAPHY(MULTIPOINTZ, 9000), geography_multiline GEOGRAPHY(MULTILINESTRING, 9000), - geography_multiline_m GEOGRAPHY(MULTILINESTRINGZ, 9000), - geography_multiline_z GEOGRAPHY(MULTILINESTRINGM, 9000), - geography_multiline_zm GEOGRAPHY(MULTILINESTRINGZM, 9000), + geography_multiline_z GEOGRAPHY(MULTILINESTRINGZ, 9000), geography_multipolygon GEOGRAPHY(MULTIPOLYGON, 9000), - geography_multipolygon_m GEOGRAPHY(MULTIPOLYGONZ, 9000), - geography_multipolygon_z GEOGRAPHY(MULTIPOLYGONM, 9000), - geography_multipolygon_zm GEOGRAPHY(MULTIPOLYGONZM, 9000), + geography_multipolygon_z GEOGRAPHY(MULTIPOLYGONZ, 9000), geography_collection GEOGRAPHY(GEOMETRYCOLLECTION, 9000), - geography_collection_m GEOGRAPHY(GEOMETRYCOLLECTIONZ, 9000), - geography_collection_z GEOGRAPHY(GEOMETRYCOLLECTIONM, 9000), - geography_collection_zm GEOGRAPHY(GEOMETRYCOLLECTIONZM, 9000) + geography_collection_z GEOGRAPHY(GEOMETRYCOLLECTIONZ, 9000) ); "#; @@ -292,14 +260,6 @@ fn all_postgis_column_types_must_work(api: TestApi) { c.assert_full_data_type("geometry") .assert_column_type_family(ColumnTypeFamily::Geometry) }) - .assert_column("geometry_geometry_m", |c| { - c.assert_full_data_type("geometry") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) - .assert_column("geometry_geometry_zm", |c| { - c.assert_full_data_type("geometry") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) .assert_column("geometry_point", |c| { c.assert_full_data_type("geometry") .assert_column_type_family(ColumnTypeFamily::Geometry) @@ -308,14 +268,6 @@ fn all_postgis_column_types_must_work(api: TestApi) { c.assert_full_data_type("geometry") .assert_column_type_family(ColumnTypeFamily::Geometry) }) - .assert_column("geometry_point_m", |c| { - c.assert_full_data_type("geometry") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) - .assert_column("geometry_point_zm", |c| { - c.assert_full_data_type("geometry") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) .assert_column("geometry_line", |c| { c.assert_full_data_type("geometry") .assert_column_type_family(ColumnTypeFamily::Geometry) @@ -324,14 +276,6 @@ fn all_postgis_column_types_must_work(api: TestApi) { c.assert_full_data_type("geometry") .assert_column_type_family(ColumnTypeFamily::Geometry) }) - .assert_column("geometry_line_m", |c| { - c.assert_full_data_type("geometry") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) - .assert_column("geometry_line_zm", |c| { - c.assert_full_data_type("geometry") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) .assert_column("geometry_polygon", |c| { c.assert_full_data_type("geometry") .assert_column_type_family(ColumnTypeFamily::Geometry) @@ -340,14 +284,6 @@ fn all_postgis_column_types_must_work(api: TestApi) { c.assert_full_data_type("geometry") .assert_column_type_family(ColumnTypeFamily::Geometry) }) - .assert_column("geometry_polygon_m", |c| { - c.assert_full_data_type("geometry") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) - .assert_column("geometry_polygon_zm", |c| { - c.assert_full_data_type("geometry") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) .assert_column("geometry_multipoint", |c| { c.assert_full_data_type("geometry") .assert_column_type_family(ColumnTypeFamily::Geometry) @@ -356,14 +292,6 @@ fn all_postgis_column_types_must_work(api: TestApi) { c.assert_full_data_type("geometry") .assert_column_type_family(ColumnTypeFamily::Geometry) }) - .assert_column("geometry_multipoint_m", |c| { - c.assert_full_data_type("geometry") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) - .assert_column("geometry_multipoint_zm", |c| { - c.assert_full_data_type("geometry") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) .assert_column("geometry_multiline", |c| { c.assert_full_data_type("geometry") .assert_column_type_family(ColumnTypeFamily::Geometry) @@ -372,14 +300,6 @@ fn all_postgis_column_types_must_work(api: TestApi) { c.assert_full_data_type("geometry") .assert_column_type_family(ColumnTypeFamily::Geometry) }) - .assert_column("geometry_multiline_m", |c| { - c.assert_full_data_type("geometry") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) - .assert_column("geometry_multiline_zm", |c| { - c.assert_full_data_type("geometry") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) .assert_column("geometry_multipolygon", |c| { c.assert_full_data_type("geometry") .assert_column_type_family(ColumnTypeFamily::Geometry) @@ -388,14 +308,6 @@ fn all_postgis_column_types_must_work(api: TestApi) { c.assert_full_data_type("geometry") .assert_column_type_family(ColumnTypeFamily::Geometry) }) - .assert_column("geometry_multipolygon_m", |c| { - c.assert_full_data_type("geometry") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) - .assert_column("geometry_multipolygon_zm", |c| { - c.assert_full_data_type("geometry") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) .assert_column("geometry_collection", |c| { c.assert_full_data_type("geometry") .assert_column_type_family(ColumnTypeFamily::Geometry) @@ -404,14 +316,6 @@ fn all_postgis_column_types_must_work(api: TestApi) { c.assert_full_data_type("geometry") .assert_column_type_family(ColumnTypeFamily::Geometry) }) - .assert_column("geometry_collection_m", |c| { - c.assert_full_data_type("geometry") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) - .assert_column("geometry_collection_zm", |c| { - c.assert_full_data_type("geometry") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) .assert_column("geography_geometry", |c| { c.assert_full_data_type("geography") .assert_column_type_family(ColumnTypeFamily::Geometry) @@ -420,14 +324,6 @@ fn all_postgis_column_types_must_work(api: TestApi) { c.assert_full_data_type("geography") .assert_column_type_family(ColumnTypeFamily::Geometry) }) - .assert_column("geography_geometry_m", |c| { - c.assert_full_data_type("geography") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) - .assert_column("geography_geometry_zm", |c| { - c.assert_full_data_type("geography") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) .assert_column("geography_point", |c| { c.assert_full_data_type("geography") .assert_column_type_family(ColumnTypeFamily::Geometry) @@ -436,14 +332,6 @@ fn all_postgis_column_types_must_work(api: TestApi) { c.assert_full_data_type("geography") .assert_column_type_family(ColumnTypeFamily::Geometry) }) - .assert_column("geography_point_m", |c| { - c.assert_full_data_type("geography") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) - .assert_column("geography_point_zm", |c| { - c.assert_full_data_type("geography") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) .assert_column("geography_line", |c| { c.assert_full_data_type("geography") .assert_column_type_family(ColumnTypeFamily::Geometry) @@ -452,14 +340,6 @@ fn all_postgis_column_types_must_work(api: TestApi) { c.assert_full_data_type("geography") .assert_column_type_family(ColumnTypeFamily::Geometry) }) - .assert_column("geography_line_m", |c| { - c.assert_full_data_type("geography") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) - .assert_column("geography_line_zm", |c| { - c.assert_full_data_type("geography") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) .assert_column("geography_polygon", |c| { c.assert_full_data_type("geography") .assert_column_type_family(ColumnTypeFamily::Geometry) @@ -468,14 +348,6 @@ fn all_postgis_column_types_must_work(api: TestApi) { c.assert_full_data_type("geography") .assert_column_type_family(ColumnTypeFamily::Geometry) }) - .assert_column("geography_polygon_m", |c| { - c.assert_full_data_type("geography") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) - .assert_column("geography_polygon_zm", |c| { - c.assert_full_data_type("geography") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) .assert_column("geography_multipoint", |c| { c.assert_full_data_type("geography") .assert_column_type_family(ColumnTypeFamily::Geometry) @@ -484,14 +356,6 @@ fn all_postgis_column_types_must_work(api: TestApi) { c.assert_full_data_type("geography") .assert_column_type_family(ColumnTypeFamily::Geometry) }) - .assert_column("geography_multipoint_m", |c| { - c.assert_full_data_type("geography") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) - .assert_column("geography_multipoint_zm", |c| { - c.assert_full_data_type("geography") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) .assert_column("geography_multiline", |c| { c.assert_full_data_type("geography") .assert_column_type_family(ColumnTypeFamily::Geometry) @@ -500,14 +364,6 @@ fn all_postgis_column_types_must_work(api: TestApi) { c.assert_full_data_type("geography") .assert_column_type_family(ColumnTypeFamily::Geometry) }) - .assert_column("geography_multiline_m", |c| { - c.assert_full_data_type("geography") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) - .assert_column("geography_multiline_zm", |c| { - c.assert_full_data_type("geography") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) .assert_column("geography_multipolygon", |c| { c.assert_full_data_type("geography") .assert_column_type_family(ColumnTypeFamily::Geometry) @@ -516,14 +372,6 @@ fn all_postgis_column_types_must_work(api: TestApi) { c.assert_full_data_type("geography") .assert_column_type_family(ColumnTypeFamily::Geometry) }) - .assert_column("geography_multipolygon_m", |c| { - c.assert_full_data_type("geography") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) - .assert_column("geography_multipolygon_zm", |c| { - c.assert_full_data_type("geography") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) .assert_column("geography_collection", |c| { c.assert_full_data_type("geography") .assert_column_type_family(ColumnTypeFamily::Geometry) @@ -532,14 +380,6 @@ fn all_postgis_column_types_must_work(api: TestApi) { c.assert_full_data_type("geography") .assert_column_type_family(ColumnTypeFamily::Geometry) }) - .assert_column("geography_collection_m", |c| { - c.assert_full_data_type("geography") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) - .assert_column("geography_collection_zm", |c| { - c.assert_full_data_type("geography") - .assert_column_type_family(ColumnTypeFamily::Geometry) - }) }); } From c7a5ed311a50181149373b47a9171db2f241b4eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Fri, 4 Oct 2024 00:28:32 +0200 Subject: [PATCH 059/103] Fix quaint geometry as raw --- quaint/src/visitor/mssql.rs | 5 +++-- quaint/src/visitor/mysql.rs | 4 ++-- quaint/src/visitor/postgres.rs | 4 ++-- quaint/src/visitor/sqlite.rs | 4 ++-- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/quaint/src/visitor/mssql.rs b/quaint/src/visitor/mssql.rs index 15b5ae0324b7..d27314968bd3 100644 --- a/quaint/src/visitor/mssql.rs +++ b/quaint/src/visitor/mssql.rs @@ -424,10 +424,10 @@ impl<'a> Visitor<'a> for Mssql<'a> { // TODO@geometry: find a way to avoid cloning ValueType::Geometry(g) => g .as_ref() - .map(|g| self.visit_function(geom_from_text(g.wkt.clone(), g.srid, false))), + .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.map(IntoRaw::raw), false))), ValueType::Geography(g) => g .as_ref() - .map(|g| self.visit_function(geom_from_text(g.wkt.clone(), g.srid, true))), + .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.map(IntoRaw::raw), true))), }; match res { @@ -839,6 +839,7 @@ impl<'a> Visitor<'a> for Mssql<'a> { self.write(if geom.geography { "geography" } else { "geometry" })?; self.surround_with("::STGeomFromText(", ")", |ref mut s| { s.visit_expression(*geom.wkt_expression)?; + s.write(",")?; if geom.geography { s.visit_expression(*geom.srid_expression.unwrap_or_else(|| Box::new(4326.into())))?; } else { diff --git a/quaint/src/visitor/mysql.rs b/quaint/src/visitor/mysql.rs index dd3c67720b39..fbe596d9fdc7 100644 --- a/quaint/src/visitor/mysql.rs +++ b/quaint/src/visitor/mysql.rs @@ -196,10 +196,10 @@ impl<'a> Visitor<'a> for Mysql<'a> { // TODO@geometry: find a way to avoid cloning ValueType::Geometry(g) => g .as_ref() - .map(|g| self.visit_function(geom_from_text(g.wkt.clone(), g.srid, false))), + .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.map(IntoRaw::raw), false))), ValueType::Geography(g) => g .as_ref() - .map(|g| self.visit_function(geom_from_text(g.wkt.clone(), g.srid, true))), + .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.map(IntoRaw::raw), true))), }; match res { diff --git a/quaint/src/visitor/postgres.rs b/quaint/src/visitor/postgres.rs index c0ff38666338..658648994fb4 100644 --- a/quaint/src/visitor/postgres.rs +++ b/quaint/src/visitor/postgres.rs @@ -260,10 +260,10 @@ impl<'a> Visitor<'a> for Postgres<'a> { // TODO@geometry: find a way to avoid cloning ValueType::Geometry(g) => g .as_ref() - .map(|g| self.visit_function(geom_from_text(g.wkt.clone(), g.srid, false))), + .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.map(IntoRaw::raw), false))), ValueType::Geography(g) => g .as_ref() - .map(|g| self.visit_function(geom_from_text(g.wkt.clone(), g.srid, true))), + .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.map(IntoRaw::raw), true))), }; match res { diff --git a/quaint/src/visitor/sqlite.rs b/quaint/src/visitor/sqlite.rs index c20d6fd9f0b2..99cc169c7213 100644 --- a/quaint/src/visitor/sqlite.rs +++ b/quaint/src/visitor/sqlite.rs @@ -143,10 +143,10 @@ impl<'a> Visitor<'a> for Sqlite<'a> { // TODO@geometry: find a way to avoid cloning ValueType::Geometry(g) => g .as_ref() - .map(|g| self.visit_function(geom_from_text(g.wkt.clone(), g.srid, false))), + .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.map(IntoRaw::raw), false))), ValueType::Geography(g) => g .as_ref() - .map(|g| self.visit_function(geom_from_text(g.wkt.clone(), g.srid, true))), + .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.map(IntoRaw::raw), true))), }; match res { From 128c12d67841895131e30caf2cf550f63df09ee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Fri, 4 Oct 2024 00:40:10 +0200 Subject: [PATCH 060/103] Fix spatialite schema describer tests --- .../describers/sqlite_describer_tests.rs | 306 +----------------- 1 file changed, 1 insertion(+), 305 deletions(-) diff --git a/schema-engine/sql-schema-describer/tests/describers/sqlite_describer_tests.rs b/schema-engine/sql-schema-describer/tests/describers/sqlite_describer_tests.rs index 05619cc3b71a..e1469946d4d3 100644 --- a/schema-engine/sql-schema-describer/tests/describers/sqlite_describer_tests.rs +++ b/schema-engine/sql-schema-describer/tests/describers/sqlite_describer_tests.rs @@ -221,36 +221,20 @@ fn spatialite_column_types_must_work(api: TestApi) { SELECT AddGeometryColumn('User', 'geometry_xy', 4326, 'GEOMETRY', 'XY', 0), AddGeometryColumn('User', 'geometry_xyz', 4326, 'GEOMETRY', 'XYZ', 0), - AddGeometryColumn('User', 'geometry_xym', 4326, 'GEOMETRY', 'XYM', 0), - AddGeometryColumn('User', 'geometry_xyzm', 4326, 'GEOMETRY', 'XYZM', 0), AddGeometryColumn('User', 'point_xy', 4326, 'POINT', 'XY', 0), AddGeometryColumn('User', 'point_xyz', 4326, 'POINT', 'XYZ', 0), - AddGeometryColumn('User', 'point_xym', 4326, 'POINT', 'XYM', 0), - AddGeometryColumn('User', 'point_xyzm', 4326, 'POINT', 'XYZM', 0), AddGeometryColumn('User', 'linestring_xy', 4326, 'LINESTRING', 'XY', 0), AddGeometryColumn('User', 'linestring_xyz', 4326, 'LINESTRING', 'XYZ', 0), - AddGeometryColumn('User', 'linestring_xym', 4326, 'LINESTRING', 'XYM', 0), - AddGeometryColumn('User', 'linestring_xyzm', 4326, 'LINESTRING', 'XYZM', 0), AddGeometryColumn('User', 'polygon_xy', 4326, 'POLYGON', 'XY', 0), AddGeometryColumn('User', 'polygon_xyz', 4326, 'POLYGON', 'XYZ', 0), - AddGeometryColumn('User', 'polygon_xym', 4326, 'POLYGON', 'XYM', 0), - AddGeometryColumn('User', 'polygon_xyzm', 4326, 'POLYGON', 'XYZM', 0), AddGeometryColumn('User', 'multipoint_xy', 4326, 'MULTIPOINT', 'XY', 0), AddGeometryColumn('User', 'multipoint_xyz', 4326, 'MULTIPOINT', 'XYZ', 0), - AddGeometryColumn('User', 'multipoint_xym', 4326, 'MULTIPOINT', 'XYM', 0), - AddGeometryColumn('User', 'multipoint_xyzm', 4326, 'MULTIPOINT', 'XYZM', 0), AddGeometryColumn('User', 'multilinestring_xy', 4326, 'MULTILINESTRING', 'XY', 0), AddGeometryColumn('User', 'multilinestring_xyz', 4326, 'MULTILINESTRING', 'XYZ', 0), - AddGeometryColumn('User', 'multilinestring_xym', 4326, 'MULTILINESTRING', 'XYM', 0), - AddGeometryColumn('User', 'multilinestring_xyzm', 4326, 'MULTILINESTRING', 'XYZM', 0), AddGeometryColumn('User', 'multipolygon_xy', 4326, 'MULTIPOLYGON', 'XY', 0), AddGeometryColumn('User', 'multipolygon_xyz', 4326, 'MULTIPOLYGON', 'XYZ', 0), - AddGeometryColumn('User', 'multipolygon_xym', 4326, 'MULTIPOLYGON', 'XYM', 0), - AddGeometryColumn('User', 'multipolygon_xyzm', 4326, 'MULTIPOLYGON', 'XYZM', 0), AddGeometryColumn('User', 'geometrycollection_xy', 4326, 'GEOMETRYCOLLECTION', 'XY', 0), - AddGeometryColumn('User', 'geometrycollection_xyz', 4326, 'GEOMETRYCOLLECTION', 'XYZ', 0), - AddGeometryColumn('User', 'geometrycollection_xym', 4326, 'GEOMETRYCOLLECTION', 'XYM', 0), - AddGeometryColumn('User', 'geometrycollection_xyzm', 4326, 'GEOMETRYCOLLECTION', 'XYZM', 0); + AddGeometryColumn('User', 'geometrycollection_xyz', 4326, 'GEOMETRYCOLLECTION', 'XYZ', 0); "#; api.raw_cmd(sql); let expectation = expect![[r#" @@ -323,42 +307,6 @@ fn spatialite_column_types_must_work(api: TestApi) { description: None, }, ), - ( - TableId( - 0, - ), - Column { - name: "geometry_xym", - tpe: ColumnType { - full_data_type: "GEOMETRY", - family: Geometry, - arity: Nullable, - native_type: Some( - NativeTypeInstance(..), - ), - }, - auto_increment: false, - description: None, - }, - ), - ( - TableId( - 0, - ), - Column { - name: "geometry_xyzm", - tpe: ColumnType { - full_data_type: "GEOMETRY", - family: Geometry, - arity: Nullable, - native_type: Some( - NativeTypeInstance(..), - ), - }, - auto_increment: false, - description: None, - }, - ), ( TableId( 0, @@ -395,42 +343,6 @@ fn spatialite_column_types_must_work(api: TestApi) { description: None, }, ), - ( - TableId( - 0, - ), - Column { - name: "point_xym", - tpe: ColumnType { - full_data_type: "POINT", - family: Geometry, - arity: Nullable, - native_type: Some( - NativeTypeInstance(..), - ), - }, - auto_increment: false, - description: None, - }, - ), - ( - TableId( - 0, - ), - Column { - name: "point_xyzm", - tpe: ColumnType { - full_data_type: "POINT", - family: Geometry, - arity: Nullable, - native_type: Some( - NativeTypeInstance(..), - ), - }, - auto_increment: false, - description: None, - }, - ), ( TableId( 0, @@ -467,42 +379,6 @@ fn spatialite_column_types_must_work(api: TestApi) { description: None, }, ), - ( - TableId( - 0, - ), - Column { - name: "linestring_xym", - tpe: ColumnType { - full_data_type: "LINESTRING", - family: Geometry, - arity: Nullable, - native_type: Some( - NativeTypeInstance(..), - ), - }, - auto_increment: false, - description: None, - }, - ), - ( - TableId( - 0, - ), - Column { - name: "linestring_xyzm", - tpe: ColumnType { - full_data_type: "LINESTRING", - family: Geometry, - arity: Nullable, - native_type: Some( - NativeTypeInstance(..), - ), - }, - auto_increment: false, - description: None, - }, - ), ( TableId( 0, @@ -539,42 +415,6 @@ fn spatialite_column_types_must_work(api: TestApi) { description: None, }, ), - ( - TableId( - 0, - ), - Column { - name: "polygon_xym", - tpe: ColumnType { - full_data_type: "POLYGON", - family: Geometry, - arity: Nullable, - native_type: Some( - NativeTypeInstance(..), - ), - }, - auto_increment: false, - description: None, - }, - ), - ( - TableId( - 0, - ), - Column { - name: "polygon_xyzm", - tpe: ColumnType { - full_data_type: "POLYGON", - family: Geometry, - arity: Nullable, - native_type: Some( - NativeTypeInstance(..), - ), - }, - auto_increment: false, - description: None, - }, - ), ( TableId( 0, @@ -611,42 +451,6 @@ fn spatialite_column_types_must_work(api: TestApi) { description: None, }, ), - ( - TableId( - 0, - ), - Column { - name: "multipoint_xym", - tpe: ColumnType { - full_data_type: "MULTIPOINT", - family: Geometry, - arity: Nullable, - native_type: Some( - NativeTypeInstance(..), - ), - }, - auto_increment: false, - description: None, - }, - ), - ( - TableId( - 0, - ), - Column { - name: "multipoint_xyzm", - tpe: ColumnType { - full_data_type: "MULTIPOINT", - family: Geometry, - arity: Nullable, - native_type: Some( - NativeTypeInstance(..), - ), - }, - auto_increment: false, - description: None, - }, - ), ( TableId( 0, @@ -683,42 +487,6 @@ fn spatialite_column_types_must_work(api: TestApi) { description: None, }, ), - ( - TableId( - 0, - ), - Column { - name: "multilinestring_xym", - tpe: ColumnType { - full_data_type: "MULTILINESTRING", - family: Geometry, - arity: Nullable, - native_type: Some( - NativeTypeInstance(..), - ), - }, - auto_increment: false, - description: None, - }, - ), - ( - TableId( - 0, - ), - Column { - name: "multilinestring_xyzm", - tpe: ColumnType { - full_data_type: "MULTILINESTRING", - family: Geometry, - arity: Nullable, - native_type: Some( - NativeTypeInstance(..), - ), - }, - auto_increment: false, - description: None, - }, - ), ( TableId( 0, @@ -755,42 +523,6 @@ fn spatialite_column_types_must_work(api: TestApi) { description: None, }, ), - ( - TableId( - 0, - ), - Column { - name: "multipolygon_xym", - tpe: ColumnType { - full_data_type: "MULTIPOLYGON", - family: Geometry, - arity: Nullable, - native_type: Some( - NativeTypeInstance(..), - ), - }, - auto_increment: false, - description: None, - }, - ), - ( - TableId( - 0, - ), - Column { - name: "multipolygon_xyzm", - tpe: ColumnType { - full_data_type: "MULTIPOLYGON", - family: Geometry, - arity: Nullable, - native_type: Some( - NativeTypeInstance(..), - ), - }, - auto_increment: false, - description: None, - }, - ), ( TableId( 0, @@ -827,42 +559,6 @@ fn spatialite_column_types_must_work(api: TestApi) { description: None, }, ), - ( - TableId( - 0, - ), - Column { - name: "geometrycollection_xym", - tpe: ColumnType { - full_data_type: "GEOMETRYCOLLECTION", - family: Geometry, - arity: Nullable, - native_type: Some( - NativeTypeInstance(..), - ), - }, - auto_increment: false, - description: None, - }, - ), - ( - TableId( - 0, - ), - Column { - name: "geometrycollection_xyzm", - tpe: ColumnType { - full_data_type: "GEOMETRYCOLLECTION", - family: Geometry, - arity: Nullable, - native_type: Some( - NativeTypeInstance(..), - ), - }, - auto_increment: false, - description: None, - }, - ), ], foreign_keys: [], table_default_values: [], From 280a3d38770490238c96858c6b5a220e164db780 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Fri, 4 Oct 2024 01:29:10 +0200 Subject: [PATCH 061/103] Revert CI spatialite setup --- .github/workflows/test-query-engine-template.yml | 4 +++- .github/workflows/test-schema-engine.yml | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-query-engine-template.yml b/.github/workflows/test-query-engine-template.yml index fe9b42e6fd5c..83cd62f15344 100644 --- a/.github/workflows/test-query-engine-template.yml +++ b/.github/workflows/test-query-engine-template.yml @@ -73,14 +73,16 @@ jobs: - name: Install Spatialite if: ${{ inputs.name == 'spatialite' }} - run: sudo apt install -y libsqlite3-mod-spatialite && echo "SPATIALITE_PATH=mod_spatialite" >> $GITHUB_ENV + run: sudo apt install -y libsqlite3-mod-spatialite - run: export WORKSPACE_ROOT=$(pwd) && cargo nextest run -p query-engine-tests --partition hash:${{ matrix.partition }} --test-threads=1 if: ${{ inputs.single_threaded }} env: CLICOLOR_FORCE: 1 + SPATIALITE_PATH: ${{ inputs.name == 'spatialite' && 'mod_spatialite' || null }} - run: export WORKSPACE_ROOT=$(pwd) && cargo nextest run -p query-engine-tests --partition hash:${{ matrix.partition }} --test-threads=8 if: ${{ !inputs.single_threaded }} env: CLICOLOR_FORCE: 1 + SPATIALITE_PATH: ${{ inputs.name == 'spatialite' && 'mod_spatialite' || null }} diff --git a/.github/workflows/test-schema-engine.yml b/.github/workflows/test-schema-engine.yml index 177870ac8b49..b1c8e0e84929 100644 --- a/.github/workflows/test-schema-engine.yml +++ b/.github/workflows/test-schema-engine.yml @@ -130,7 +130,7 @@ jobs: - name: Install Spatialite if: ${{ matrix.database.name == 'spatialite' }} - run: sudo apt install -y libsqlite3-mod-spatialite && echo "SPATIALITE_PATH=mod_spatialite" >> $GITHUB_ENV + run: sudo apt install -y libsqlite3-mod-spatialite - name: "Start ${{ matrix.database.name }}" run: make start-${{ matrix.database.name }} @@ -140,24 +140,28 @@ jobs: env: CLICOLOR_FORCE: 1 TEST_DATABASE_URL: ${{ matrix.database.url }} + SPATIALITE_PATH: ${{ matrix.database.name == 'spatialite' && 'mod_spatialite' || null }} - run: cargo nextest run -p sql-schema-describer if: ${{ !matrix.database.single_threaded }} env: CLICOLOR_FORCE: 1 TEST_DATABASE_URL: ${{ matrix.database.url }} + SPATIALITE_PATH: ${{ matrix.database.name == 'spatialite' && 'mod_spatialite' || null }} - run: cargo nextest run -p sql-migration-tests if: ${{ !matrix.database.single_threaded }} env: CLICOLOR_FORCE: 1 TEST_DATABASE_URL: ${{ matrix.database.url }} + SPATIALITE_PATH: ${{ matrix.database.name == 'spatialite' && 'mod_spatialite' || null }} - run: cargo nextest run -p schema-engine-cli if: ${{ !matrix.database.single_threaded }} env: CLICOLOR_FORCE: 1 TEST_DATABASE_URL: ${{ matrix.database.url }} + SPATIALITE_PATH: ${{ matrix.database.name == 'spatialite' && 'mod_spatialite' || null }} # # Vitess tests From 0cdaaa27f286900009be28398654d16ba9c7cf31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Fri, 4 Oct 2024 01:54:20 +0200 Subject: [PATCH 062/103] Fix lint errors --- psl/parser-database/src/lib.rs | 4 +++- .../src/walkers/relation/two_way_embedded_many_to_many.rs | 8 +++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/psl/parser-database/src/lib.rs b/psl/parser-database/src/lib.rs index 5ada8cebb961..6492f7c3446e 100644 --- a/psl/parser-database/src/lib.rs +++ b/psl/parser-database/src/lib.rs @@ -55,7 +55,9 @@ pub use types::{ }; /// ParserDatabase is a container for a Schema AST, together with information -/// gathered during schema validation. Each validation step enriches the +/// gathered during schema validation. +/// +/// Each validation step enriches the /// database with information that can be used to work with the schema, without /// changing the AST. Instantiating with `ParserDatabase::new()` will perform a /// number of validations and make sure the schema makes sense, but it cannot diff --git a/psl/parser-database/src/walkers/relation/two_way_embedded_many_to_many.rs b/psl/parser-database/src/walkers/relation/two_way_embedded_many_to_many.rs index 2e125321fea5..eb1c0c08d50d 100644 --- a/psl/parser-database/src/walkers/relation/two_way_embedded_many_to_many.rs +++ b/psl/parser-database/src/walkers/relation/two_way_embedded_many_to_many.rs @@ -3,9 +3,11 @@ use crate::{ walkers::{ModelWalker, RelationFieldWalker, RelationWalker}, }; -/// Describes an explicit m:n relation between two models. Both sides define -/// `fields` which must be a single array scalar field, and `references` that -/// should point to a single scalar field on the referenced model. +/// Describes an explicit m:n relation between two models. +/// +/// Both sides define `fields` which must be a single array scalar field, +/// and `references` that should point to a single scalar field on the +/// referenced model. #[derive(Copy, Clone)] pub struct TwoWayEmbeddedManyToManyRelationWalker<'db>(pub(super) RelationWalker<'db>); From ea9e1e7ebdd5836a9f40bcff3b706672bd1482b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Fri, 4 Oct 2024 01:54:41 +0200 Subject: [PATCH 063/103] Revert CI spatialite setup --- .github/workflows/test-query-engine-template.yml | 4 +--- .github/workflows/test-schema-engine.yml | 6 +----- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/.github/workflows/test-query-engine-template.yml b/.github/workflows/test-query-engine-template.yml index 83cd62f15344..fe9b42e6fd5c 100644 --- a/.github/workflows/test-query-engine-template.yml +++ b/.github/workflows/test-query-engine-template.yml @@ -73,16 +73,14 @@ jobs: - name: Install Spatialite if: ${{ inputs.name == 'spatialite' }} - run: sudo apt install -y libsqlite3-mod-spatialite + run: sudo apt install -y libsqlite3-mod-spatialite && echo "SPATIALITE_PATH=mod_spatialite" >> $GITHUB_ENV - run: export WORKSPACE_ROOT=$(pwd) && cargo nextest run -p query-engine-tests --partition hash:${{ matrix.partition }} --test-threads=1 if: ${{ inputs.single_threaded }} env: CLICOLOR_FORCE: 1 - SPATIALITE_PATH: ${{ inputs.name == 'spatialite' && 'mod_spatialite' || null }} - run: export WORKSPACE_ROOT=$(pwd) && cargo nextest run -p query-engine-tests --partition hash:${{ matrix.partition }} --test-threads=8 if: ${{ !inputs.single_threaded }} env: CLICOLOR_FORCE: 1 - SPATIALITE_PATH: ${{ inputs.name == 'spatialite' && 'mod_spatialite' || null }} diff --git a/.github/workflows/test-schema-engine.yml b/.github/workflows/test-schema-engine.yml index b1c8e0e84929..177870ac8b49 100644 --- a/.github/workflows/test-schema-engine.yml +++ b/.github/workflows/test-schema-engine.yml @@ -130,7 +130,7 @@ jobs: - name: Install Spatialite if: ${{ matrix.database.name == 'spatialite' }} - run: sudo apt install -y libsqlite3-mod-spatialite + run: sudo apt install -y libsqlite3-mod-spatialite && echo "SPATIALITE_PATH=mod_spatialite" >> $GITHUB_ENV - name: "Start ${{ matrix.database.name }}" run: make start-${{ matrix.database.name }} @@ -140,28 +140,24 @@ jobs: env: CLICOLOR_FORCE: 1 TEST_DATABASE_URL: ${{ matrix.database.url }} - SPATIALITE_PATH: ${{ matrix.database.name == 'spatialite' && 'mod_spatialite' || null }} - run: cargo nextest run -p sql-schema-describer if: ${{ !matrix.database.single_threaded }} env: CLICOLOR_FORCE: 1 TEST_DATABASE_URL: ${{ matrix.database.url }} - SPATIALITE_PATH: ${{ matrix.database.name == 'spatialite' && 'mod_spatialite' || null }} - run: cargo nextest run -p sql-migration-tests if: ${{ !matrix.database.single_threaded }} env: CLICOLOR_FORCE: 1 TEST_DATABASE_URL: ${{ matrix.database.url }} - SPATIALITE_PATH: ${{ matrix.database.name == 'spatialite' && 'mod_spatialite' || null }} - run: cargo nextest run -p schema-engine-cli if: ${{ !matrix.database.single_threaded }} env: CLICOLOR_FORCE: 1 TEST_DATABASE_URL: ${{ matrix.database.url }} - SPATIALITE_PATH: ${{ matrix.database.name == 'spatialite' && 'mod_spatialite' || null }} # # Vitess tests From fbc748eac04ca3f4b1d43cdbceda62aa6bcdc7f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Sat, 5 Oct 2024 11:50:12 +0200 Subject: [PATCH 064/103] Defer GeoJSON conversion to quaint, using is_selected column property --- Cargo.lock | 8 +- psl/parser-database/src/lib.rs | 2 +- .../relation/two_way_embedded_many_to_many.rs | 2 +- .../cockroach_datamodel_connector.rs | 4 - .../src/builtin_connectors/geometry.rs | 10 ++- .../mysql_datamodel_connector.rs | 2 - .../postgres_datamodel_connector.rs | 4 - .../sqlite_datamodel_connector.rs | 3 - psl/psl-core/src/datamodel_connector.rs | 4 - .../src/datamodel_connector/capabilities.rs | 4 - quaint/Cargo.toml | 1 + quaint/src/ast.rs | 2 +- quaint/src/ast/column.rs | 8 ++ quaint/src/ast/expression.rs | 4 +- quaint/src/ast/function.rs | 12 ++- quaint/src/ast/function/geom_as_geojson.rs | 31 ++++++++ quaint/src/ast/function/geom_from_geojson.rs | 35 +++++++++ quaint/src/ast/values.rs | 75 +++---------------- quaint/src/connector/mssql/conversion.rs | 0 .../src/connector/mysql/native/conversion.rs | 28 +------ .../connector/postgres/native/conversion.rs | 20 ----- .../src/connector/sqlite/native/conversion.rs | 10 --- quaint/src/error/mod.rs | 6 ++ quaint/src/visitor.rs | 55 +++++++++++--- quaint/src/visitor/mssql.rs | 57 +++++++++++--- quaint/src/visitor/mysql.rs | 55 +++++++------- quaint/src/visitor/postgres.rs | 68 +++++++++++------ quaint/src/visitor/sqlite.rs | 67 ++++++++++------- .../writes/data_types/native_types/mysql.rs | 36 ++++----- .../data_types/native_types/postgres.rs | 41 +++++----- .../writes/data_types/native_types/sqlite.rs | 20 ++--- .../writes/top_level_mutations/create.rs | 5 +- .../mongodb-query-connector/src/value.rs | 1 - .../connectors/sql-query-connector/Cargo.toml | 1 + .../sql-query-connector/src/geometry.rs | 18 +++++ .../connectors/sql-query-connector/src/lib.rs | 1 + .../src/model_extensions/column.rs | 1 + .../src/model_extensions/scalar_field.rs | 39 +++++++--- .../src/query_builder/read.rs | 15 +--- .../src/query_builder/write.rs | 1 - .../connectors/sql-query-connector/src/row.rs | 41 +++++----- query-engine/query-structure/src/field/mod.rs | 5 ++ .../query-structure/src/field/scalar.rs | 2 +- .../src/sql_renderer/postgres_renderer.rs | 1 - .../tests/native_types/postgres.rs | 30 ++++---- 45 files changed, 473 insertions(+), 362 deletions(-) create mode 100644 quaint/src/ast/function/geom_as_geojson.rs create mode 100644 quaint/src/ast/function/geom_from_geojson.rs delete mode 100644 quaint/src/connector/mssql/conversion.rs create mode 100644 query-engine/connectors/sql-query-connector/src/geometry.rs diff --git a/Cargo.lock b/Cargo.lock index a1a859e45682..1ccd9006006d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -2664,7 +2664,7 @@ dependencies = [ [[package]] name = "mongodb" version = "3.0.0" -source = "git+https://github.com/prisma/mongo-rust-driver.git?branch=RUST-1994/happy-eyeballs#31e0356391a7871bec000ae35fe0edc35582449e" +source = "git+https://github.com/prisma/mongo-rust-driver.git?branch=RUST-1994%2Fhappy-eyeballs#31e0356391a7871bec000ae35fe0edc35582449e" dependencies = [ "async-trait", "base64 0.13.1", @@ -2721,7 +2721,7 @@ dependencies = [ [[package]] name = "mongodb-internal-macros" version = "3.0.0" -source = "git+https://github.com/prisma/mongo-rust-driver.git?branch=RUST-1994/happy-eyeballs#31e0356391a7871bec000ae35fe0edc35582449e" +source = "git+https://github.com/prisma/mongo-rust-driver.git?branch=RUST-1994%2Fhappy-eyeballs#31e0356391a7871bec000ae35fe0edc35582449e" dependencies = [ "proc-macro2", "quote", @@ -3850,6 +3850,7 @@ dependencies = [ "either", "expect-test", "futures", + "geojson", "geozero 0.11.0", "getrandom 0.2.11", "hex", @@ -5337,6 +5338,7 @@ dependencies = [ "cuid", "expect-test", "futures", + "geojson", "geozero 0.10.0", "itertools 0.12.0", "once_cell", diff --git a/psl/parser-database/src/lib.rs b/psl/parser-database/src/lib.rs index 6492f7c3446e..07b9e1d44879 100644 --- a/psl/parser-database/src/lib.rs +++ b/psl/parser-database/src/lib.rs @@ -56,7 +56,7 @@ pub use types::{ /// ParserDatabase is a container for a Schema AST, together with information /// gathered during schema validation. -/// +/// /// Each validation step enriches the /// database with information that can be used to work with the schema, without /// changing the AST. Instantiating with `ParserDatabase::new()` will perform a diff --git a/psl/parser-database/src/walkers/relation/two_way_embedded_many_to_many.rs b/psl/parser-database/src/walkers/relation/two_way_embedded_many_to_many.rs index eb1c0c08d50d..5d759911609f 100644 --- a/psl/parser-database/src/walkers/relation/two_way_embedded_many_to_many.rs +++ b/psl/parser-database/src/walkers/relation/two_way_embedded_many_to_many.rs @@ -4,7 +4,7 @@ use crate::{ }; /// Describes an explicit m:n relation between two models. -/// +/// /// Both sides define `fields` which must be a single array scalar field, /// and `references` that should point to a single scalar field on the /// referenced model. 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 2967ef88dff9..4cec7868d4b1 100644 --- a/psl/psl-core/src/builtin_connectors/cockroach_datamodel_connector.rs +++ b/psl/psl-core/src/builtin_connectors/cockroach_datamodel_connector.rs @@ -47,11 +47,7 @@ const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(Connector JsonFiltering | JsonFilteringArrayPath | Geometry | - GeometryRawRead | - GeometryGeoJsonIO | GeometryFiltering | - GeometryExtraDims | - GeometryExtraTypes | NamedPrimaryKeys | NamedForeignKeys | SqlQueryRaw | diff --git a/psl/psl-core/src/builtin_connectors/geometry.rs b/psl/psl-core/src/builtin_connectors/geometry.rs index a2972cf1fdc3..b3ef5d4de6d9 100644 --- a/psl/psl-core/src/builtin_connectors/geometry.rs +++ b/psl/psl-core/src/builtin_connectors/geometry.rs @@ -139,6 +139,11 @@ impl crate::datamodel_connector::NativeTypeArguments for GeometryParams { const REQUIRED_ARGUMENTS_COUNT: usize = 2; fn from_parts(parts: &[String]) -> Option { + // GeometryParams is used in Postgres, Cockroach and SQlite. For the three of them, + // the database type for the primsa Geometry type is db.Geometry(Geometry, 0). + // We don't want to force the users to think about what SRID they should choose + // in case they're only interested in setting the geometry type, so in such + // case we manually set the SRID to 0 here. match parts { [geom] => GeometryType::from_str(geom).ok().map(|ty| Self { type_: ty, srid: 0 }), [geom, srid] => GeometryType::from_str(geom) @@ -149,9 +154,6 @@ impl crate::datamodel_connector::NativeTypeArguments for GeometryParams { } fn to_parts(&self) -> Vec { - match self.srid { - 0 => vec![self.type_.to_string()], - srid => vec![self.type_.to_string(), srid.to_string()], - } + vec![self.type_.to_string(), self.srid.to_string()] } } diff --git a/psl/psl-core/src/builtin_connectors/mysql_datamodel_connector.rs b/psl/psl-core/src/builtin_connectors/mysql_datamodel_connector.rs index a400132ea403..ca0319052444 100644 --- a/psl/psl-core/src/builtin_connectors/mysql_datamodel_connector.rs +++ b/psl/psl-core/src/builtin_connectors/mysql_datamodel_connector.rs @@ -38,9 +38,7 @@ pub const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(Conne EnumArrayPush | Json | Geometry | - GeometryRawRead | GeometryFiltering | - GeometryGeoJsonIO | AutoIncrementAllowedOnNonId | RelationFieldsInArbitraryOrder | CreateMany | diff --git a/psl/psl-core/src/builtin_connectors/postgres_datamodel_connector.rs b/psl/psl-core/src/builtin_connectors/postgres_datamodel_connector.rs index d64b29cef8c5..3f7066c08139 100644 --- a/psl/psl-core/src/builtin_connectors/postgres_datamodel_connector.rs +++ b/psl/psl-core/src/builtin_connectors/postgres_datamodel_connector.rs @@ -51,11 +51,7 @@ pub const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(Conne JsonFilteringAlphanumeric | JsonFilteringAlphanumericFieldRef | Geometry | - GeometryRawRead | - GeometryGeoJsonIO | GeometryFiltering | - GeometryExtraDims | - GeometryExtraTypes | MultiSchema | NamedForeignKeys | NamedPrimaryKeys | diff --git a/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs b/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs index e5043bc4e204..a9034e178d74 100644 --- a/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs +++ b/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs @@ -19,10 +19,7 @@ pub const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(Conne AutoIncrement | CompoundIds | Geometry | - GeometryRawRead | - GeometryGeoJsonIO | GeometryFiltering | - GeometryExtraDims | SqlQueryRaw | RelationFieldsInArbitraryOrder | UpdateableId | diff --git a/psl/psl-core/src/datamodel_connector.rs b/psl/psl-core/src/datamodel_connector.rs index 64a95fd3c4d0..d269f6c958f7 100644 --- a/psl/psl-core/src/datamodel_connector.rs +++ b/psl/psl-core/src/datamodel_connector.rs @@ -227,10 +227,6 @@ pub trait Connector: Send + Sync { self.capabilities().contains(ConnectorCapability::Geometry) } - fn supports_raw_geometry_read(&self) -> bool { - self.capabilities().contains(ConnectorCapability::GeometryRawRead) - } - fn supported_index_types(&self) -> BitFlags { IndexAlgorithm::BTree.into() } diff --git a/psl/psl-core/src/datamodel_connector/capabilities.rs b/psl/psl-core/src/datamodel_connector/capabilities.rs index e55839c74339..0f441fb99657 100644 --- a/psl/psl-core/src/datamodel_connector/capabilities.rs +++ b/psl/psl-core/src/datamodel_connector/capabilities.rs @@ -56,11 +56,7 @@ capabilities!( ImplicitManyToManyRelation, MultiSchema, Geometry, - GeometryGeoJsonIO, - GeometryRawRead, GeometryFiltering, - GeometryExtraDims, - GeometryExtraTypes, //Start of ME/IE only capabilities AutoIncrementAllowedOnNonId, AutoIncrementMultipleAllowed, diff --git a/quaint/Cargo.toml b/quaint/Cargo.toml index 7ee632146d91..6b06d5bee221 100644 --- a/quaint/Cargo.toml +++ b/quaint/Cargo.toml @@ -86,6 +86,7 @@ crosstarget-utils = { path = "../libs/crosstarget-utils" } concat-idents = "1.1.5" once_cell = "1.3" geozero = { version = "0.11.0", default-features = false, features = ["with-wkb", "with-geojson"] } +geojson = { version = "0.24.1", default-features = false } [dev-dependencies] once_cell = "1.3" diff --git a/quaint/src/ast.rs b/quaint/src/ast.rs index 4bf2004e1e51..c899697a1d80 100644 --- a/quaint/src/ast.rs +++ b/quaint/src/ast.rs @@ -53,5 +53,5 @@ pub use select::{DistinctType, Select}; pub use table::*; pub use union::Union; pub use update::*; -pub use values::{GeometryValue, IntoRaw, Raw, Value, ValueType, Values}; +pub use values::{IntoRaw, Raw, Value, ValueType, Values}; pub(crate) use values::{NativeColumnType, Params}; diff --git a/quaint/src/ast/column.rs b/quaint/src/ast/column.rs index f53b5f41379e..ee3276d9657e 100644 --- a/quaint/src/ast/column.rs +++ b/quaint/src/ast/column.rs @@ -40,6 +40,8 @@ pub struct Column<'a> { pub(crate) is_enum: bool, /// Whether the column is a (scalar) list. pub(crate) is_list: bool, + /// Whether the column is a geometry. + pub(crate) is_geometry: bool, /// Whether the column is part of a SELECT or RETURNING clause. pub(crate) is_selected: bool, } @@ -111,6 +113,12 @@ impl<'a> Column<'a> { self } + /// Sets whether the column points to an geometry type. + pub fn set_is_geometry(mut self, is_geometry: bool) -> Self { + self.is_geometry = is_geometry; + self + } + /// Sets whether the column is selected. /// /// On Postgres, this defines whether an enum column should be casted to `TEXT` when rendered. diff --git a/quaint/src/ast/expression.rs b/quaint/src/ast/expression.rs index 69da03682e19..34de5741b6bc 100644 --- a/quaint/src/ast/expression.rs +++ b/quaint/src/ast/expression.rs @@ -257,9 +257,7 @@ impl<'a> ExpressionKind<'a> { typed: ValueType::Geography(_), .. })) => true, - Self::Column(c) if matches!(c.type_family, Some(TypeFamily::Geography(_) | TypeFamily::Geometry(_))) => { - true - } + Self::Column(c) if c.is_geometry => true, Self::Function(f) => f.returns_geometry(), Self::Value(expr) => expr.is_geometry_expr(), _ => false, diff --git a/quaint/src/ast/function.rs b/quaint/src/ast/function.rs index 9b0bdb1f86ad..20adf494292d 100644 --- a/quaint/src/ast/function.rs +++ b/quaint/src/ast/function.rs @@ -17,7 +17,9 @@ mod search; mod sum; mod upper; +mod geom_as_geojson; mod geom_as_text; +mod geom_from_geojson; mod geom_from_text; mod uuid; @@ -41,7 +43,9 @@ pub use search::*; pub use sum::*; pub use upper::*; +pub use geom_as_geojson::*; pub use geom_as_text::*; +pub use geom_from_geojson::*; pub use geom_from_text::*; pub use self::uuid::*; @@ -67,7 +71,10 @@ impl<'a> Function<'a> { ) } pub fn returns_geometry(&self) -> bool { - matches!(self.typ_, FunctionType::GeomFromText(_)) + matches!( + self.typ_, + FunctionType::GeomFromText(_) | FunctionType::GeomFromGeoJson(_) + ) } } @@ -99,6 +106,8 @@ pub(crate) enum FunctionType<'a> { Uuid, GeomAsText(GeomAsText<'a>), GeomFromText(GeomFromText<'a>), + GeomAsGeoJson(GeomAsGeoJson<'a>), + GeomFromGeoJson(GeomFromGeoJson<'a>), } impl<'a> Aliasable<'a> for Function<'a> { @@ -146,3 +155,4 @@ function!( ); function!(GeomAsText, GeomFromText); +function!(GeomAsGeoJson, GeomFromGeoJson); diff --git a/quaint/src/ast/function/geom_as_geojson.rs b/quaint/src/ast/function/geom_as_geojson.rs new file mode 100644 index 000000000000..db814a81b782 --- /dev/null +++ b/quaint/src/ast/function/geom_as_geojson.rs @@ -0,0 +1,31 @@ +use super::Function; +use crate::ast::Expression; + +/// A represention of the `ST_AsGeoJSON` function in the database. +#[derive(Debug, Clone, PartialEq)] +pub struct GeomAsGeoJson<'a> { + pub(crate) expression: Box>, +} + +/// Read the geometry expression into a GeoJson object. +/// +/// ```rust +/// # use quaint::{ast::*, visitor::{Visitor, Sqlite}}; +/// # fn main() -> Result<(), quaint::error::Error> { +/// let query = Select::from_table("users").value(geom_as_geojson(Column::from("location"))); +/// let (sql, _) = Sqlite::build(query)?; +/// +/// assert_eq!("SELECT AsGeoJSON(`location`) FROM `users`", sql); +/// # Ok(()) +/// # } +/// ``` +pub fn geom_as_geojson<'a, E>(expression: E) -> Function<'a> +where + E: Into>, +{ + let fun = GeomAsGeoJson { + expression: Box::new(expression.into()), + }; + + fun.into() +} diff --git a/quaint/src/ast/function/geom_from_geojson.rs b/quaint/src/ast/function/geom_from_geojson.rs new file mode 100644 index 000000000000..6ee667b5f9d6 --- /dev/null +++ b/quaint/src/ast/function/geom_from_geojson.rs @@ -0,0 +1,35 @@ +use super::Function; +use crate::ast::Expression; + +/// A represention of the `ST_AsText` function in the database. +#[derive(Debug, Clone, PartialEq)] +pub struct GeomFromGeoJson<'a> { + pub(crate) expression: Box>, +} + +/// Write a GeoJson geometry value using built-in database conversion. +/// +/// ```rust +/// # use quaint::{ast::*, visitor::{Visitor, Sqlite}}; +/// # fn main() -> Result<(), quaint::error::Error> { +/// let query = Insert::single_into("users").value("location", geom_from_geojson("POINT(0 0)")); +/// let (sql, params) = Sqlite::build(query)?; +/// +/// assert_eq!("INSERT INTO `users` (`location`) VALUES (GeomFromGeoJSON(?))", sql); +/// +/// assert_eq!(vec![ +/// Value::from("POINT(0 0)"), +/// ], params); +/// # Ok(()) +/// # } +/// ``` +pub fn geom_from_geojson<'a, G>(expression: G) -> Function<'a> +where + G: Into>, +{ + let fun = GeomFromGeoJson { + expression: Box::new(expression.into()), + }; + + fun.into() +} diff --git a/quaint/src/ast/values.rs b/quaint/src/ast/values.rs index e3226adfd6ac..2ea069860206 100644 --- a/quaint/src/ast/values.rs +++ b/quaint/src/ast/values.rs @@ -5,7 +5,7 @@ use bigdecimal::{BigDecimal, FromPrimitive, ToPrimitive}; use chrono::{DateTime, NaiveDate, NaiveTime, Utc}; use serde_json::{Number, Value as JsonValue}; -use std::fmt::{Display, Formatter}; +use std::fmt::Display; use std::{ borrow::{Borrow, Cow}, convert::TryFrom, @@ -14,9 +14,6 @@ use std::{ }; use uuid::Uuid; -use once_cell::sync::Lazy; -use regex::Regex; - /// A value written to the query as-is without parameterization. #[derive(Debug, Clone, PartialEq)] pub struct Raw<'a>(pub(crate) Value<'a>); @@ -37,42 +34,6 @@ where } } -#[derive(Debug, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] -pub struct GeometryValue { - pub wkt: String, - pub srid: Option, -} - -impl Display for GeometryValue { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self.srid { - None | Some(0) => (), - Some(srid) => write!(f, "SRID={};", srid)?, - } - f.write_str(&self.wkt) - } -} - -impl FromStr for GeometryValue { - type Err = Error; - - fn from_str(s: &str) -> Result { - static EWKT_REGEX: Lazy = Lazy::new(|| Regex::new(r"^(SRID=(?P\d+);)?(?P.+)$").unwrap()); - EWKT_REGEX - .captures(s) - .map(|capture| { - let srid = capture - .name("srid") - .map(|v| v.as_str().parse::()) - .transpose() - .map_err(|_| Error::builder(ErrorKind::conversion("Invalid EWKT SRID")).build())?; - let wkt = capture.name("geometry").map(|v| v.as_str()).unwrap().to_string(); - Ok(GeometryValue { srid, wkt }) - }) - .ok_or_else(|| Error::builder(ErrorKind::conversion("Invalid EWKT string")).build())? - } -} - /// A native-column type, i.e. the connector-specific type of the column. #[derive(Debug, Clone, PartialEq)] pub struct NativeColumnType<'a> { @@ -265,18 +226,12 @@ impl<'a> Value<'a> { } /// Creates a new geometry value. - pub fn geometry(value: T) -> Self - where - T: Into, - { + pub fn geometry(value: geojson::Geometry) -> Self { ValueType::geometry(value).into_value() } - /// Creates a new geography value. - pub fn geography(value: T) -> Self - where - T: Into, - { + /// Creates a new geometry value. + pub fn geography(value: geojson::Geometry) -> Self { ValueType::geography(value).into_value() } @@ -606,9 +561,9 @@ pub enum ValueType<'a> { /// A JSON value. Json(Option), /// A Geometry value. - Geometry(Option), + Geometry(Option), /// A Geography value. - Geography(Option), + Geography(Option), /// A XML value. Xml(Option>), /// An UUID value. @@ -893,20 +848,14 @@ impl<'a> ValueType<'a> { Self::Json(Some(value)) } - /// Creates a new geometry value. - pub fn geometry(value: T) -> Self - where - T: Into, - { - Self::Geometry(Some(value.into())) + /// Creates a new GeoJSON geometry value. + pub(crate) fn geometry(value: geojson::Geometry) -> Self { + Self::Geometry(Some(value)) } - /// Creates a new geometry value. - pub fn geography(value: T) -> Self - where - T: Into, - { - Self::Geography(Some(value.into())) + /// Creates a new GeoJSON geography value. + pub(crate) fn geography(value: geojson::Geometry) -> Self { + Self::Geography(Some(value)) } /// Creates a new XML value. diff --git a/quaint/src/connector/mssql/conversion.rs b/quaint/src/connector/mssql/conversion.rs deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/quaint/src/connector/mysql/native/conversion.rs b/quaint/src/connector/mysql/native/conversion.rs index a05cdabf8dc4..6bece29fd0b1 100644 --- a/quaint/src/connector/mysql/native/conversion.rs +++ b/quaint/src/connector/mysql/native/conversion.rs @@ -4,7 +4,6 @@ use crate::{ error::{Error, ErrorKind}, }; use chrono::{DateTime, Datelike, NaiveDate, NaiveDateTime, NaiveTime, Timelike, Utc}; -use geozero::{wkb::MySQLWkb, wkt::WktStr, ToWkb, ToWkt}; use mysql_async::{ self as my, consts::{ColumnFlags, ColumnType}, @@ -69,23 +68,8 @@ pub fn conv_params(params: &[Value<'_>]) -> crate::Result { dt.timestamp_subsec_micros(), ) }), - ValueType::Geometry(g) | ValueType::Geography(g) => match g { - None => None, - Some(ref g) => { - let res = WktStr(&g.wkt).to_mysql_wkb(g.srid).map(my::Value::Bytes); - - if res.is_err() { - let msg = "Couldn't convert value `{g}` into EWKB."; - let kind = ErrorKind::conversion(msg); - - let mut builder = Error::builder(kind); - builder.set_original_message(msg); - - return Err(builder.build()); - } - Some(res.unwrap()) - } - }, + ValueType::Geometry(_) => panic!("Cannot handle raw Geometry"), + ValueType::Geography(_) => panic!("Cannot handle raw Geography"), }; match res { @@ -282,14 +266,6 @@ impl TakeRow for my::Row { [0] => Value::boolean(false), _ => Value::boolean(true), }, - my::Value::Bytes(b) if column.is_geometry() => { - MySQLWkb(b).to_ewkt(None).map(Value::text).map_err(|_| { - let msg = "Could not convert geometry blob to Ewkt"; - let kind = ErrorKind::conversion(msg); - - Error::builder(kind).build() - })? - } // https://dev.mysql.com/doc/internals/en/character-set.html my::Value::Bytes(b) if column.character_set() == 63 => Value::bytes(b), my::Value::Bytes(s) => Value::text(String::from_utf8(s)?), diff --git a/quaint/src/connector/postgres/native/conversion.rs b/quaint/src/connector/postgres/native/conversion.rs index 8a5c21080a2e..81eb0e98c993 100644 --- a/quaint/src/connector/postgres/native/conversion.rs +++ b/quaint/src/connector/postgres/native/conversion.rs @@ -15,7 +15,6 @@ use bytes::BytesMut; use chrono::{DateTime, NaiveDateTime, Utc}; pub(crate) use decimal::DecimalWrapper; -use geozero::{wkb::Ewkb, ToWkt}; use postgres_types::{FromSql, ToSql, WrongType}; use std::{borrow::Cow, convert::TryFrom, error::Error as StdError}; use tokio_postgres::{ @@ -107,18 +106,6 @@ pub(crate) fn params_to_types(params: &[Value<'_>]) -> Vec { .collect() } -struct EwktString(pub String); - -impl<'a> FromSql<'a> for EwktString { - fn from_sql(_ty: &PostgresType, raw: &'a [u8]) -> Result> { - Ok(Ewkb(raw.to_owned()).to_ewkt(None).map(EwktString)?) - } - - fn accepts(ty: &PostgresType) -> bool { - matches!(ty.name(), "geometry" | "geography") - } -} - struct XmlString(pub String); impl<'a> FromSql<'a> for XmlString { @@ -682,13 +669,6 @@ impl GetRow for PostgresRow { } } }?, - PGColumnType::Unknown(_) if matches!(pg_ty.name(), "geometry" | "geography") => { - let val: Option = row.try_get(i)?; - match val { - Some(ewkt) => ValueType::Text(Some(ewkt.0.into())), - None => ValueType::Text(None), - } - } PGColumnType::Unknown(v) => match row.try_get(i) { Ok(Some(val)) => { let val: String = val; diff --git a/quaint/src/connector/sqlite/native/conversion.rs b/quaint/src/connector/sqlite/native/conversion.rs index 7518cc936b0e..ea6a9d1cfbdc 100644 --- a/quaint/src/connector/sqlite/native/conversion.rs +++ b/quaint/src/connector/sqlite/native/conversion.rs @@ -9,7 +9,6 @@ use crate::{ error::{Error, ErrorKind}, }; -use geozero::{wkb::SpatiaLiteWkb, ToWkt}; use rusqlite::{ types::{Null, ToSql, ToSqlOutput, ValueRef}, Column, Error as RusqlError, Row as SqliteRow, Rows as SqliteRows, @@ -238,15 +237,6 @@ impl<'a> GetRow for SqliteRow<'a> { }) })? } - ValueRef::Blob(bytes) if column.is_geometry() => SpatiaLiteWkb(bytes.to_vec()) - .to_ewkt(None) - .map(Value::text) - .map_err(|_| { - let builder = Error::builder(ErrorKind::ConversionError( - "Failed to read contents of SQLite geometry column as WKT".into(), - )); - builder.build() - })?, ValueRef::Text(bytes) => Value::text(String::from_utf8(bytes.to_vec())?), ValueRef::Blob(bytes) => Value::bytes(bytes.to_owned()), }; diff --git a/quaint/src/error/mod.rs b/quaint/src/error/mod.rs index 661eb4d344ff..6cc1e46b9115 100644 --- a/quaint/src/error/mod.rs +++ b/quaint/src/error/mod.rs @@ -298,6 +298,12 @@ impl From for Error { } } +impl From for Error { + fn from(_: geozero::error::GeozeroError) -> Self { + Self::builder(ErrorKind::conversion("Malformed GeoJSON data.")).build() + } +} + impl From for Error { fn from(_: std::fmt::Error) -> Self { Self::builder(ErrorKind::conversion("Problems writing AST into a query string.")).build() diff --git a/quaint/src/visitor.rs b/quaint/src/visitor.rs index 20a523dd6059..e3e9908ac319 100644 --- a/quaint/src/visitor.rs +++ b/quaint/src/visitor.rs @@ -141,6 +141,14 @@ pub trait Visitor<'a> { fn visit_geom_from_text(&mut self, geom: GeomFromText<'a>) -> Result; + fn visit_geom_as_geojson(&mut self, _geom: GeomAsGeoJson<'a>) -> Result { + unimplemented!("GeomAsGeoJson not supported for the underlying database.") + } + + fn visit_geom_from_geojson(&mut self, _geom: GeomFromGeoJson<'a>) -> Result { + unimplemented!("GeomFromGeoJson not supported for the underlying database.") + } + fn visit_geometry_type_equals(&mut self, left: Expression<'a>, right: GeometryType<'a>, not: bool) -> Result; fn visit_geometry_empty(&mut self, left: Expression<'a>, not: bool) -> Result { @@ -217,14 +225,22 @@ pub trait Visitor<'a> { Ok(()) } + fn visit_parameterized_geometry(&mut self, geometry: geojson::Geometry) -> Result { + self.visit_function(geom_from_geojson(geometry.to_string())) + } + + fn visit_parameterized_geography(&mut self, geometry: geojson::Geometry) -> Result { + self.visit_function(geom_from_geojson(geometry.to_string())) + } + /// A visit to a value we parameterize fn visit_parameterized(&mut self, value: Value<'a>) -> Result { match value.typed { ValueType::Enum(Some(variant), name) => self.visit_parameterized_enum(variant, name), ValueType::EnumArray(Some(variants), name) => self.visit_parameterized_enum_array(variants, name), ValueType::Text(txt) => self.visit_parameterized_text(txt, value.native_column_type), - ValueType::Geometry(Some(geom)) => self.visit_function(geom_from_text(geom.wkt, geom.srid, false)), - ValueType::Geography(Some(geom)) => self.visit_function(geom_from_text(geom.wkt, geom.srid, true)), + ValueType::Geometry(Some(geometry)) => self.visit_parameterized_geometry(geometry), + ValueType::Geography(Some(geometry)) => self.visit_parameterized_geometry(geometry), ValueType::Geometry(None) | ValueType::Geography(None) => self.write("NULL"), _ => { self.add_parameter(value); @@ -722,18 +738,29 @@ pub trait Visitor<'a> { Ok(()) } + fn visit_geometry_column(&mut self, mut column: Column<'a>) -> Result { + column.alias = None; + column.is_selected = false; + self.visit_function(geom_as_geojson(column)) + } + /// A database column identifier fn visit_column(&mut self, column: Column<'a>) -> Result { - match column.table { - Some(table) => { - self.visit_table(table, false)?; - self.write(".")?; - self.delimited_identifiers(&[&*column.name])?; - } - _ => self.delimited_identifiers(&[&*column.name])?, - }; + let alias = column.alias.clone(); + if column.is_geometry && column.is_selected { + self.visit_geometry_column(column)?; + } else { + match column.table { + Some(table) => { + self.visit_table(table, false)?; + self.write(".")?; + self.delimited_identifiers(&[&*column.name])?; + } + _ => self.delimited_identifiers(&[&*column.name])?, + }; + } - if let Some(alias) = column.alias { + if let Some(alias) = alias { self.write(" AS ")?; self.delimited_identifiers(&[&*alias])?; } @@ -1196,6 +1223,12 @@ pub trait Visitor<'a> { FunctionType::GeomFromText(geom) => { self.visit_geom_from_text(geom)?; } + FunctionType::GeomAsGeoJson(geom) => { + self.visit_geom_as_geojson(geom)?; + } + FunctionType::GeomFromGeoJson(geom) => { + self.visit_geom_from_geojson(geom)?; + } }; if let Some(alias) = fun.alias { diff --git a/quaint/src/visitor/mssql.rs b/quaint/src/visitor/mssql.rs index d27314968bd3..c71384ffe1d8 100644 --- a/quaint/src/visitor/mssql.rs +++ b/quaint/src/visitor/mssql.rs @@ -1,3 +1,5 @@ +use geozero::ToWkt; + use super::{NativeColumnType, Visitor}; #[cfg(any(feature = "postgresql", feature = "mysql"))] use crate::prelude::{JsonArrayAgg, JsonBuildObject, JsonExtract, JsonType, JsonUnquote}; @@ -20,6 +22,28 @@ pub struct Mssql<'a> { order_by_set: bool, } +fn get_geometry_srid(geom: &geojson::Geometry) -> Option { + geom.foreign_members + .as_ref()? + .get("crs")? + .as_object()? + .get("properties")? + .as_object()? + .get("name")? + .as_str()? + .rsplit_once(":")? + .1 + .parse() + .ok() +} + +fn geojson_to_wkt_srid(geometry: &geojson::Geometry) -> crate::Result<(String, i32)> { + let srid = get_geometry_srid(geometry) + .ok_or_else(|| Error::builder(ErrorKind::QueryInvalidInput("Invalid SRID in GeoJSON CRS".into())).build())?; + let wkt = geozero::geojson::GeoJsonString(geometry.to_string()).to_wkt()?; + Ok((wkt, srid)) +} + impl<'a> Mssql<'a> { // TODO: figure out that merge shit fn visit_returning(&mut self, columns: Vec>) -> visitor::Result { @@ -253,6 +277,16 @@ impl<'a> Visitor<'a> for Mssql<'a> { } } + fn visit_parameterized_geometry(&mut self, geometry: geojson::Geometry) -> visitor::Result { + let (wkt, srid) = geojson_to_wkt_srid(&geometry)?; + self.visit_function(geom_from_text(wkt, Some(srid), false)) + } + + fn visit_parameterized_geography(&mut self, geometry: geojson::Geometry) -> visitor::Result { + let (wkt, srid) = geojson_to_wkt_srid(&geometry)?; + self.visit_function(geom_from_text(wkt, Some(srid), true)) + } + /// A point to modify an incoming query to make it compatible with the /// SQL Server. fn compatibility_modifications(&self, query: Query<'a>) -> Query<'a> { @@ -421,13 +455,8 @@ impl<'a> Visitor<'a> for Mssql<'a> { // Style 3 is keep all whitespace + internal DTD processing: // https://docs.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql?redirectedfrom=MSDN&view=sql-server-ver15#xml-styles ValueType::Xml(cow) => cow.map(|cow| self.write(format!("CONVERT(XML, N'{cow}', 3)"))), - // TODO@geometry: find a way to avoid cloning - ValueType::Geometry(g) => g - .as_ref() - .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.map(IntoRaw::raw), false))), - ValueType::Geography(g) => g - .as_ref() - .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.map(IntoRaw::raw), true))), + ValueType::Geometry(geojson) => geojson.map(|g| self.visit_function(geom_from_geojson(g.to_string()))), + ValueType::Geography(geojson) => geojson.map(|g| self.visit_function(geom_from_geojson(g.to_string()))), }; match res { @@ -816,6 +845,11 @@ impl<'a> Visitor<'a> for Mssql<'a> { unimplemented!("JSON filtering is not yet supported on MSSQL") } + fn visit_geometry_column(&mut self, column: Column<'a>) -> visitor::Result { + // SQL Server does not support GeoJSON, so we return EWKT instead + self.visit_function(geom_as_text(column)) + } + fn visit_geom_as_text(&mut self, geom: GeomAsText<'a>) -> visitor::Result { self.write("CASE WHEN ")?; self.visit_expression(*geom.expression.clone())?; @@ -858,7 +892,6 @@ mod tests { visitor::{Mssql, Visitor}, }; use indoc::indoc; - use std::str::FromStr; fn expected_values<'a, T>(sql: &'static str, params: Vec) -> (String, Vec>) where @@ -1429,17 +1462,17 @@ mod tests { #[test] fn test_raw_geometry() { - let geom = GeometryValue::from_str("SRID=4326;POINT(0 0)").unwrap(); + let geom = r#"{"type": "Point", "coordinates": [1, 2]}"#.parse::().unwrap(); let (sql, params) = Mssql::build(Select::default().value(Value::geometry(geom).raw())).unwrap(); - assert_eq!("SELECT geometry::STGeomFromText('POINT(0 0)',4326)", sql); + assert_eq!("SELECT geometry::STGeomFromText('POINT(1 2)',0)", sql); assert!(params.is_empty()); } #[test] fn test_raw_geography() { - let geom = GeometryValue::from_str("SRID=4326;POINT(0 0)").unwrap(); + let geom = r#"{"type": "Point", "coordinates": [1, 2]}"#.parse::().unwrap(); let (sql, params) = Mssql::build(Select::default().value(Value::geography(geom).raw())).unwrap(); - assert_eq!("SELECT geography::STGeomFromText('POINT(0 0)',4326)", sql); + assert_eq!("SELECT geography::STGeomFromText('POINT(1 2)',4326)", sql); assert!(params.is_empty()); } diff --git a/quaint/src/visitor/mysql.rs b/quaint/src/visitor/mysql.rs index fbe596d9fdc7..4f36b094e727 100644 --- a/quaint/src/visitor/mysql.rs +++ b/quaint/src/visitor/mysql.rs @@ -193,13 +193,12 @@ impl<'a> Visitor<'a> for Mysql<'a> { ValueType::Date(date) => date.map(|date| self.write(format!("'{date}'"))), ValueType::Time(time) => time.map(|time| self.write(format!("'{time}'"))), ValueType::Xml(cow) => cow.as_ref().map(|cow| self.write(format!("'{cow}'"))), - // TODO@geometry: find a way to avoid cloning ValueType::Geometry(g) => g .as_ref() - .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.map(IntoRaw::raw), false))), + .map(|g| self.visit_function(geom_from_geojson(g.to_string().raw()))), ValueType::Geography(g) => g .as_ref() - .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.map(IntoRaw::raw), true))), + .map(|g| self.visit_function(geom_from_geojson(g.to_string().raw()))), }; match res { @@ -311,19 +310,6 @@ impl<'a> Visitor<'a> for Mysql<'a> { } } - /// MySQL geometries *must* be handled in raw binary form to prevent it from swapping longitude and latitude - fn visit_parameterized(&mut self, value: Value<'a>) -> visitor::Result { - match value.typed { - ValueType::Enum(Some(variant), name) => self.visit_parameterized_enum(variant, name), - ValueType::EnumArray(Some(variants), name) => self.visit_parameterized_enum_array(variants, name), - ValueType::Text(txt) => self.visit_parameterized_text(txt, value.native_column_type), - _ => { - self.add_parameter(value); - self.parameter_substitution() - } - } - } - fn parameter_substitution(&mut self) -> visitor::Result { self.write("?") } @@ -735,6 +721,20 @@ impl<'a> Visitor<'a> for Mysql<'a> { Ok(()) }) } + + fn visit_geom_as_geojson(&mut self, geom: GeomAsGeoJson<'a>) -> visitor::Result { + self.surround_with("ST_AsGeoJSON(", ")", |s| { + s.visit_expression(*geom.expression)?; + s.write(", 15, 2")?; + Ok(()) + }) + } + + fn visit_geom_from_geojson(&mut self, geom: GeomFromGeoJson<'a>) -> visitor::Result { + self.surround_with("ST_GeomFromGeoJSON(", ")", |ref mut s| { + s.visit_expression(*geom.expression) + }) + } } fn get_target_table<'a>(query: &Query<'a>) -> Option> { @@ -748,7 +748,6 @@ fn get_target_table<'a>(query: &Query<'a>) -> Option> { #[cfg(test)] mod tests { use crate::visitor::*; - use std::str::FromStr; fn expected_values<'a, T>(sql: &'static str, params: Vec) -> (String, Vec>) where @@ -933,21 +932,23 @@ mod tests { #[test] fn test_raw_geometry() { - let (sql, params) = Mysql::build( - Select::default().value(Value::geometry(GeometryValue::from_str("SRID=4326;POINT(0 0)").unwrap()).raw()), - ) - .unwrap(); - assert_eq!("SELECT ST_GeomFromText('POINT(0 0)',4326)", sql); + let geom = r#"{"type": "Point", "coordinates": [1, 2]}"#.parse::().unwrap(); + let (sql, params) = Mysql::build(Select::default().value(Value::geometry(geom).raw())).unwrap(); + assert_eq!( + r#"SELECT ST_GeomFromGeoJSON('{"type":"Point","coordinates":[1,2]}')"#, + sql + ); assert!(params.is_empty()); } #[test] fn test_raw_geography() { - let (sql, params) = Mysql::build( - Select::default().value(Value::geography(GeometryValue::from_str("SRID=4326;POINT(0 0)").unwrap()).raw()), - ) - .unwrap(); - assert_eq!("SELECT ST_GeomFromText('POINT(0 0)',4326)", sql); + let geom = r#"{"type": "Point", "coordinates": [1, 2]}"#.parse::().unwrap(); + let (sql, params) = Mysql::build(Select::default().value(Value::geography(geom).raw())).unwrap(); + assert_eq!( + r#"SELECT ST_GeomFromGeoJSON('{"type":"Point","coordinates":[1,2]}')"#, + sql + ); assert!(params.is_empty()); } diff --git a/quaint/src/visitor/postgres.rs b/quaint/src/visitor/postgres.rs index 658648994fb4..aab7ef97514d 100644 --- a/quaint/src/visitor/postgres.rs +++ b/quaint/src/visitor/postgres.rs @@ -139,24 +139,28 @@ impl<'a> Visitor<'a> for Postgres<'a> { /// A database column identifier fn visit_column(&mut self, column: Column<'a>) -> visitor::Result { - match column.table { - Some(table) => { - self.visit_table(table, false)?; - self.write(".")?; - self.delimited_identifiers(&[&*column.name])?; - } - _ => self.delimited_identifiers(&[&*column.name])?, - }; - - if column.is_enum && column.is_selected { - if column.is_list { - self.write("::text[]")?; - } else { - self.write("::text")?; + let alias = column.alias.clone(); + if column.is_geometry && column.is_selected { + self.visit_geometry_column(column)?; + } else { + match column.table { + Some(table) => { + self.visit_table(table, false)?; + self.write(".")?; + self.delimited_identifiers(&[&*column.name])?; + } + _ => self.delimited_identifiers(&[&*column.name])?, + }; + if column.is_enum && column.is_selected { + if column.is_list { + self.write("::text[]")?; + } else { + self.write("::text")?; + } } } - if let Some(alias) = column.alias { + if let Some(alias) = alias { self.write(" AS ")?; self.delimited_identifiers(&[&*alias])?; } @@ -257,13 +261,12 @@ impl<'a> Visitor<'a> for Postgres<'a> { ValueType::DateTime(dt) => dt.map(|dt| self.write(format!("'{}'", dt.to_rfc3339(),))), ValueType::Date(date) => date.map(|date| self.write(format!("'{date}'"))), ValueType::Time(time) => time.map(|time| self.write(format!("'{time}'"))), - // TODO@geometry: find a way to avoid cloning ValueType::Geometry(g) => g .as_ref() - .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.map(IntoRaw::raw), false))), + .map(|g| self.visit_function(geom_from_geojson(g.to_string().raw()))), ValueType::Geography(g) => g .as_ref() - .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.map(IntoRaw::raw), true))), + .map(|g| self.visit_function(geom_from_geojson(g.to_string().raw()))), }; match res { @@ -799,12 +802,25 @@ impl<'a> Visitor<'a> for Postgres<'a> { Ok(()) }) } + + fn visit_geom_as_geojson(&mut self, geom: GeomAsGeoJson<'a>) -> visitor::Result { + self.surround_with("ST_AsGeoJSON(", ")", |s| { + s.visit_expression(*geom.expression)?; + s.write(", 15")?; + Ok(()) + }) + } + + fn visit_geom_from_geojson(&mut self, geom: GeomFromGeoJson<'a>) -> visitor::Result { + self.surround_with("ST_GeomFromGeoJSON(", ")", |ref mut s| { + s.visit_expression(*geom.expression) + }) + } } #[cfg(test)] mod tests { use crate::visitor::*; - use std::str::FromStr; fn expected_values<'a, T>(sql: &'static str, params: Vec) -> (String, Vec>) where @@ -1219,17 +1235,23 @@ mod tests { #[test] fn test_raw_geometry() { - let geom = GeometryValue::from_str("SRID=4326;POINT(0 0)").unwrap(); + let geom = r#"{"type": "Point", "coordinates": [1, 2]}"#.parse::().unwrap(); let (sql, params) = Postgres::build(Select::default().value(Value::geometry(geom).raw())).unwrap(); - assert_eq!("SELECT ST_GeomFromText('POINT(0 0)',4326)", sql); + assert_eq!( + r#"SELECT ST_GeomFromGeoJSON('{"type":"Point","coordinates":[1,2]}')"#, + sql + ); assert!(params.is_empty()); } #[test] fn test_raw_geography() { - let geom = GeometryValue::from_str("SRID=4326;POINT(0 0)").unwrap(); + let geom = r#"{"type": "Point", "coordinates": [1, 2]}"#.parse::().unwrap(); let (sql, params) = Postgres::build(Select::default().value(Value::geography(geom).raw())).unwrap(); - assert_eq!("SELECT ST_GeomFromText('POINT(0 0)',4326)", sql); + assert_eq!( + r#"SELECT ST_GeomFromGeoJSON('{"type":"Point","coordinates":[1,2]}')"#, + sql + ); assert!(params.is_empty()); } diff --git a/quaint/src/visitor/sqlite.rs b/quaint/src/visitor/sqlite.rs index 99cc169c7213..93be01f549f2 100644 --- a/quaint/src/visitor/sqlite.rs +++ b/quaint/src/visitor/sqlite.rs @@ -16,22 +16,19 @@ pub struct Sqlite<'a> { } impl<'a> Sqlite<'a> { - fn returning(&mut self, returning: Option>>) -> visitor::Result { + fn visit_returning(&mut self, returning: Option>>) -> visitor::Result { if let Some(returning) = returning { if !returning.is_empty() { - let values_len = returning.len(); + let values = returning + .into_iter() + .map(|mut r| { + let name = r.name.clone(); + r.table = None; + r.alias(name).into() + }) + .collect(); self.write(" RETURNING ")?; - - for (i, column) in returning.into_iter().enumerate() { - // Workaround for SQLite parsing bug - // https://sqlite.org/forum/info/6c141f151fa5c444db257eb4d95c302b70bfe5515901cf987e83ed8ebd434c49?t=h - self.surround_with_backticks(&column.name)?; - self.write(" AS ")?; - self.surround_with_backticks(&column.name)?; - if i < (values_len - 1) { - self.write(", ")?; - } - } + self.visit_columns(values)?; } } Ok(()) @@ -140,13 +137,12 @@ impl<'a> Visitor<'a> for Sqlite<'a> { ValueType::Date(date) => date.map(|date| self.write(format!("'{date}'"))), ValueType::Time(time) => time.map(|time| self.write(format!("'{time}'"))), ValueType::Xml(cow) => cow.as_ref().map(|cow| self.write(format!("'{cow}'"))), - // TODO@geometry: find a way to avoid cloning ValueType::Geometry(g) => g .as_ref() - .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.map(IntoRaw::raw), false))), + .map(|g| self.visit_function(geom_from_geojson(g.to_string().raw()))), ValueType::Geography(g) => g .as_ref() - .map(|g| self.visit_function(geom_from_text(g.wkt.clone().raw(), g.srid.map(IntoRaw::raw), true))), + .map(|g| self.visit_function(geom_from_geojson(g.to_string().raw()))), }; match res { @@ -228,7 +224,7 @@ impl<'a> Visitor<'a> for Sqlite<'a> { self.visit_upsert(update)?; } - self.returning(insert.returning)?; + self.visit_returning(insert.returning)?; if let Some(comment) = insert.comment { self.write(" ")?; @@ -450,7 +446,7 @@ impl<'a> Visitor<'a> for Sqlite<'a> { self.visit_conditions(conditions)?; } - self.returning(delete.returning)?; + self.visit_returning(delete.returning)?; if let Some(comment) = delete.comment { self.write(" ")?; @@ -485,7 +481,7 @@ impl<'a> Visitor<'a> for Sqlite<'a> { self.visit_conditions(conditions)?; } - self.returning(update.returning)?; + self.visit_returning(update.returning)?; if let Some(comment) = update.comment { self.write(" ")?; @@ -509,12 +505,25 @@ impl<'a> Visitor<'a> for Sqlite<'a> { Ok(()) }) } + + fn visit_geom_as_geojson(&mut self, geom: GeomAsGeoJson<'a>) -> visitor::Result { + self.surround_with("AsGeoJSON(", ")", |s| { + s.visit_expression(*geom.expression)?; + s.write(", 15, 2")?; + Ok(()) + }) + } + + fn visit_geom_from_geojson(&mut self, geom: GeomFromGeoJson<'a>) -> visitor::Result { + self.surround_with("GeomFromGeoJSON(", ")", |ref mut s| { + s.visit_expression(*geom.expression) + }) + } } #[cfg(test)] mod tests { use crate::{val, visitor::*}; - use std::str::FromStr; fn expected_values<'a, T>(sql: &'static str, params: Vec) -> (String, Vec>) where @@ -1067,17 +1076,23 @@ mod tests { #[test] fn test_raw_geometry() { - let geom = GeometryValue::from_str("SRID=4326;POINT(0 0)").unwrap(); - let (sql, params) = Postgres::build(Select::default().value(Value::geometry(geom).raw())).unwrap(); - assert_eq!("SELECT ST_GeomFromText('POINT(0 0)',4326)", sql); + let geom = r#"{"type": "Point", "coordinates": [1, 2]}"#.parse::().unwrap(); + let (sql, params) = Sqlite::build(Select::default().value(Value::geometry(geom).raw())).unwrap(); + assert_eq!( + r#"SELECT ST_GeomFromGeoJSON('{"type":"Point","coordinates":[1,2]}')"#, + sql + ); assert!(params.is_empty()); } #[test] fn test_raw_geography() { - let geom = GeometryValue::from_str("SRID=4326;POINT(0 0)").unwrap(); - let (sql, params) = Postgres::build(Select::default().value(Value::geography(geom).raw())).unwrap(); - assert_eq!("SELECT ST_GeomFromText('POINT(0 0)',4326)", sql); + let geom = r#"{"type": "Point", "coordinates": [1, 2]}"#.parse::().unwrap(); + let (sql, params) = Sqlite::build(Select::default().value(Value::geography(geom).raw())).unwrap(); + assert_eq!( + r#"SELECT ST_GeomFromGeoJSON('{"type":"Point","coordinates":[1,2]}')"#, + sql + ); assert!(params.is_empty()); } diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs index aaec4296a9c5..72455f999831 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs @@ -456,14 +456,14 @@ mod mysql { run_query!(&runner, r#"mutation { createOneModel( data: { - geometry: "{\"type\": \"Point\", \"coordinates\" :[1,2]}" - point: "{\"type\": \"Point\", \"coordinates\" :[1,2]}" - line: "{\"type\": \"LineString\", \"coordinates\" :[[1,2],[3,4]]}" - poly: "{\"type\": \"Polygon\", \"coordinates\" :[[[1,2],[3,4],[5,6],[1,2]]]}" - multipoint: "{\"type\": \"MultiPoint\", \"coordinates\" :[[1,2]]}" - multiline: "{\"type\": \"MultiLineString\", \"coordinates\" :[[[1,2],[3,4]]]}" - multipoly: "{\"type\": \"MultiPolygon\", \"coordinates\" :[[[[1,2],[3,4],[5,6],[1,2]]]]}" - collection: "{\"type\": \"GeometryCollection\",\"geometries\" :[{\"type\": \"Point\", \"coordinates\" :[1,2]}]}" + geometry: "{\"type\":\"Point\",\"coordinates\" :[1,2]}" + point: "{\"type\":\"Point\",\"coordinates\" :[1,2]}" + line: "{\"type\":\"LineString\",\"coordinates\" :[[1,2],[3,4]]}" + poly: "{\"type\":\"Polygon\",\"coordinates\" :[[[1,2],[3,4],[5,6],[1,2]]]}" + multipoint: "{\"type\":\"MultiPoint\",\"coordinates\" :[[1,2]]}" + multiline: "{\"type\":\"MultiLineString\",\"coordinates\" :[[[1,2],[3,4]]]}" + multipoly: "{\"type\":\"MultiPolygon\",\"coordinates\" :[[[[1,2],[3,4],[5,6],[1,2]]]]}" + collection: "{\"type\":\"GeometryCollection\",\"geometries\" :[{\"type\":\"Point\",\"coordinates\" :[1,2]}]}" } ) { geometry, @@ -476,7 +476,7 @@ mod mysql { collection } }"#), - @r###"{"data":{"createOneModel":{"geometry":"{\"type\": \"Point\", \"coordinates\": [1,2]}","point":"{\"type\": \"Point\", \"coordinates\": [1,2]}","line":"{\"type\": \"LineString\", \"coordinates\": [[1,2],[3,4]]}","poly":"{\"type\": \"Polygon\", \"coordinates\": [[[1,2],[3,4],[5,6],[1,2]]]}","multipoint":"{\"type\": \"MultiPoint\", \"coordinates\": [[1,2]]}","multiline":"{\"type\": \"MultiLineString\", \"coordinates\": [[[1,2],[3,4]]]}","multipoly":"{\"type\": \"MultiPolygon\", \"coordinates\": [[[[1,2],[3,4],[5,6],[1,2]]]]}","collection":"{\"type\": \"GeometryCollection\", \"geometries\": [{\"type\": \"Point\", \"coordinates\": [1,2]}]}"}}}"### + @r###"{"data":{"createOneModel":{"geometry":"{\"coordinates\":[1,2],\"type\":\"Point\"}","point":"{\"coordinates\":[1,2],\"type\":\"Point\"}","line":"{\"coordinates\":[[1,2],[3,4]],\"type\":\"LineString\"}","poly":"{\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]],\"type\":\"Polygon\"}","multipoint":"{\"coordinates\":[[1,2]],\"type\":\"MultiPoint\"}","multiline":"{\"coordinates\":[[[1,2],[3,4]]],\"type\":\"MultiLineString\"}","multipoly":"{\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]],\"type\":\"MultiPolygon\"}","collection":"{\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}],\"type\":\"GeometryCollection\"}"}}}"### ); Ok(()) @@ -507,14 +507,14 @@ mod mysql { run_query!(&runner, r#"mutation { createOneModel( data: { - geometry: "{\"type\": \"Point\", \"coordinates\" :[1,2]}" - point: "{\"type\": \"Point\", \"coordinates\" :[1,2]}" - line: "{\"type\": \"LineString\", \"coordinates\" :[[1,2],[3,4]]}" - poly: "{\"type\": \"Polygon\", \"coordinates\" :[[[1,2],[3,4],[5,6],[1,2]]]}" - multipoint: "{\"type\": \"MultiPoint\", \"coordinates\" :[[1,2]]}" - multiline: "{\"type\": \"MultiLineString\", \"coordinates\" :[[[1,2],[3,4]]]}" - multipoly: "{\"type\": \"MultiPolygon\", \"coordinates\" :[[[[1,2],[3,4],[5,6],[1,2]]]]}" - collection: "{\"type\": \"GeometryCollection\",\"geometries\" :[{\"type\": \"Point\", \"coordinates\" :[1,2]}]}" + geometry: "{\"type\":\"Point\",\"coordinates\" :[1,2]}" + point: "{\"type\":\"Point\",\"coordinates\" :[1,2]}" + line: "{\"type\":\"LineString\",\"coordinates\" :[[1,2],[3,4]]}" + poly: "{\"type\":\"Polygon\",\"coordinates\" :[[[1,2],[3,4],[5,6],[1,2]]]}" + multipoint: "{\"type\":\"MultiPoint\",\"coordinates\" :[[1,2]]}" + multiline: "{\"type\":\"MultiLineString\",\"coordinates\" :[[[1,2],[3,4]]]}" + multipoly: "{\"type\":\"MultiPolygon\",\"coordinates\" :[[[[1,2],[3,4],[5,6],[1,2]]]]}" + collection: "{\"type\":\"GeometryCollection\",\"geometries\" :[{\"type\":\"Point\",\"coordinates\" :[1,2]}]}" } ) { geometry, @@ -527,7 +527,7 @@ mod mysql { collection } }"#), - @r###"{"data":{"createOneModel":{"geometry":"{\"type\": \"Point\", \"coordinates\": [1,2]}","point":"{\"type\": \"Point\", \"coordinates\": [1,2]}","line":"{\"type\": \"LineString\", \"coordinates\": [[1,2],[3,4]]}","poly":"{\"type\": \"Polygon\", \"coordinates\": [[[1,2],[3,4],[5,6],[1,2]]]}","multipoint":"{\"type\": \"MultiPoint\", \"coordinates\": [[1,2]]}","multiline":"{\"type\": \"MultiLineString\", \"coordinates\": [[[1,2],[3,4]]]}","multipoly":"{\"type\": \"MultiPolygon\", \"coordinates\": [[[[1,2],[3,4],[5,6],[1,2]]]]}","collection":"{\"type\": \"GeometryCollection\", \"geometries\": [{\"type\": \"Point\", \"coordinates\": [1,2]}]}"}}}"### + @r###"{"data":{"createOneModel":{"geometry":"{\"type\":\"Point\",\"coordinates\":[1,2]}","point":"{\"type\":\"Point\",\"coordinates\":[1,2]}","line":"{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}","poly":"{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}","multipoint":"{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}","multiline":"{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}","multipoly":"{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}","collection":"{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}"}}}"### ); Ok(()) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/postgres.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/postgres.rs index b4452f4e14a8..fa21c57e8574 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/postgres.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/postgres.rs @@ -397,7 +397,7 @@ mod postgres { geometry_collection } }"#), - @r###"{"data":{"createOneModel":{"geometry":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geometry_point":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geometry_line":"{\"type\": \"LineString\", \"coordinates\": [[1,2],[3,4]]}","geometry_poly":"{\"type\": \"Polygon\", \"coordinates\": [[[1,2],[3,4],[5,6],[1,2]]]}","geometry_multipoint":"{\"type\": \"MultiPoint\", \"coordinates\": [[1,2]]}","geometry_multiline":"{\"type\": \"MultiLineString\", \"coordinates\": [[[1,2],[3,4]]]}","geometry_multipoly":"{\"type\": \"MultiPolygon\", \"coordinates\": [[[[1,2],[3,4],[5,6],[1,2]]]]}","geometry_collection":"{\"type\": \"GeometryCollection\", \"geometries\": [{\"type\": \"Point\", \"coordinates\": [1,2]}]}"}}}"### + @r###"{"data":{"createOneModel":{"geometry":"{\"type\":\"Point\",\"coordinates\":[1,2]}","geometry_point":"{\"type\":\"Point\",\"coordinates\":[1,2]}","geometry_line":"{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}","geometry_poly":"{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}","geometry_multipoint":"{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}","geometry_multiline":"{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}","geometry_multipoly":"{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}","geometry_collection":"{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}"}}}"### ); Ok(()) @@ -428,19 +428,20 @@ mod postgres { schema(schema_geometry_srid), db_schemas("public", "test") )] + async fn native_geometry_srid(runner: Runner) -> TestResult<()> { insta::assert_snapshot!( run_query!(&runner, r#"mutation { createOneModel( data: { - geometry: "{\"type\":\"Point\",\"coordinates\":[1,2]}" - geometry_point: "{\"type\":\"Point\",\"coordinates\":[1,2]}" - geometry_line: "{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}" - geometry_poly: "{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}" - geometry_multipoint: "{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}" - geometry_multiline: "{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}" - geometry_multipoly: "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}" - geometry_collection: "{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}" + geometry: "{\"type\":\"Point\",\"coordinates\":[1,2],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}}}" + geometry_point: "{\"type\":\"Point\",\"coordinates\":[1,2],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}}}" + geometry_line: "{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}}}" + geometry_poly: "{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}}}" + geometry_multipoint: "{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}}}" + geometry_multiline: "{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}}}" + geometry_multipoly: "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}}}" + geometry_collection: "{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}}}" } ) { geometry @@ -453,7 +454,7 @@ mod postgres { geometry_collection } }"#), - @r###"{"data":{"createOneModel":{"geometry":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geometry_point":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geometry_line":"{\"type\": \"LineString\", \"coordinates\": [[1,2],[3,4]]}","geometry_poly":"{\"type\": \"Polygon\", \"coordinates\": [[[1,2],[3,4],[5,6],[1,2]]]}","geometry_multipoint":"{\"type\": \"MultiPoint\", \"coordinates\": [[1,2]]}","geometry_multiline":"{\"type\": \"MultiLineString\", \"coordinates\": [[[1,2],[3,4]]]}","geometry_multipoly":"{\"type\": \"MultiPolygon\", \"coordinates\": [[[[1,2],[3,4],[5,6],[1,2]]]]}","geometry_collection":"{\"type\": \"GeometryCollection\", \"geometries\": [{\"type\": \"Point\", \"coordinates\": [1,2]}]}"}}}"### + @r###"{"data":{"createOneModel":{"geometry":"{\"type\":\"Point\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}},\"coordinates\":[1,2]}","geometry_point":"{\"type\":\"Point\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}},\"coordinates\":[1,2]}","geometry_line":"{\"type\":\"LineString\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}},\"coordinates\":[[1,2],[3,4]]}","geometry_poly":"{\"type\":\"Polygon\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}},\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}","geometry_multipoint":"{\"type\":\"MultiPoint\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}},\"coordinates\":[[1,2]]}","geometry_multiline":"{\"type\":\"MultiLineString\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}},\"coordinates\":[[[1,2],[3,4]]]}","geometry_multipoly":"{\"type\":\"MultiPolygon\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}},\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}","geometry_collection":"{\"type\":\"GeometryCollection\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}},\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}"}}}"### ); Ok(()) @@ -509,7 +510,7 @@ mod postgres { geography_collection } }"#), - @r###"{"data":{"createOneModel":{"geography":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geography_point":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geography_line":"{\"type\": \"LineString\", \"coordinates\": [[1,2],[3,4]]}","geography_poly":"{\"type\": \"Polygon\", \"coordinates\": [[[1,2],[3,4],[5,6],[1,2]]]}","geography_multipoint":"{\"type\": \"MultiPoint\", \"coordinates\": [[1,2]]}","geography_multiline":"{\"type\": \"MultiLineString\", \"coordinates\": [[[1,2],[3,4]]]}","geography_multipoly":"{\"type\": \"MultiPolygon\", \"coordinates\": [[[[1,2],[3,4],[5,6],[1,2]]]]}","geography_collection":"{\"type\": \"GeometryCollection\", \"geometries\": [{\"type\": \"Point\", \"coordinates\": [1,2]}]}"}}}"### + @r###"{"data":{"createOneModel":{"geography":"{\"type\":\"Point\",\"coordinates\":[1,2]}","geography_point":"{\"type\":\"Point\",\"coordinates\":[1,2]}","geography_line":"{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}","geography_poly":"{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}","geography_multipoint":"{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}","geography_multiline":"{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}","geography_multipoly":"{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}","geography_collection":"{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}"}}}"### ); Ok(()) @@ -545,14 +546,14 @@ mod postgres { run_query!(&runner, r#"mutation { createOneModel( data: { - geography: "{\"type\":\"Point\",\"coordinates\":[1,2]}" - geography_point: "{\"type\":\"Point\",\"coordinates\":[1,2]}" - geography_line: "{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}" - geography_poly: "{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}" - geography_multipoint: "{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}" - geography_multiline: "{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}" - geography_multipoly: "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}" - geography_collection: "{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}" + geography: "{\"type\":\"Point\",\"coordinates\":[1,2],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:9000\"}}}" + geography_point: "{\"type\":\"Point\",\"coordinates\":[1,2],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:9000\"}}}" + geography_line: "{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:9000\"}}}" + geography_poly: "{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:9000\"}}}" + geography_multipoint: "{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:9000\"}}}" + geography_multiline: "{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:9000\"}}}" + geography_multipoly: "{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:9000\"}}}" + geography_collection: "{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:9000\"}}}" } ) { geography @@ -565,7 +566,7 @@ mod postgres { geography_collection } }"#), - @r###"{"data":{"createOneModel":{"geography":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geography_point":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geography_line":"{\"type\": \"LineString\", \"coordinates\": [[1,2],[3,4]]}","geography_poly":"{\"type\": \"Polygon\", \"coordinates\": [[[1,2],[3,4],[5,6],[1,2]]]}","geography_multipoint":"{\"type\": \"MultiPoint\", \"coordinates\": [[1,2]]}","geography_multiline":"{\"type\": \"MultiLineString\", \"coordinates\": [[[1,2],[3,4]]]}","geography_multipoly":"{\"type\": \"MultiPolygon\", \"coordinates\": [[[[1,2],[3,4],[5,6],[1,2]]]]}","geography_collection":"{\"type\": \"GeometryCollection\", \"geometries\": [{\"type\": \"Point\", \"coordinates\": [1,2]}]}"}}}"### + @r###"{"data":{"createOneModel":{"geography":"{\"type\":\"Point\",\"coordinates\":[1,2]}","geography_point":"{\"type\":\"Point\",\"coordinates\":[1,2]}","geography_line":"{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}","geography_poly":"{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}","geography_multipoint":"{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}","geography_multiline":"{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}","geography_multipoly":"{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}","geography_collection":"{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}"}}}"### ); Ok(()) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sqlite.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sqlite.rs index 770eb1d8b96a..27360c622f7f 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sqlite.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sqlite.rs @@ -9,14 +9,14 @@ mod sqlite { let schema = indoc! { r#"model Model { #id(id, String, @id, @default(cuid())) - geometry Geometry @test.Geometry(Geometry, 4326) - geometry_point Geometry @test.Geometry(Point, 4326) - geometry_line Geometry @test.Geometry(LineString, 4326) - geometry_poly Geometry @test.Geometry(Polygon, 4326) - geometry_multipoint Geometry @test.Geometry(MultiPoint, 4326) - geometry_multiline Geometry @test.Geometry(MultiLineString, 4326) - geometry_multipoly Geometry @test.Geometry(MultiPolygon, 4326) - geometry_collection Geometry @test.Geometry(GeometryCollection, 4326) + geometry Geometry @test.Geometry(Geometry) + geometry_point Geometry @test.Geometry(Point) + geometry_line Geometry @test.Geometry(LineString) + geometry_poly Geometry @test.Geometry(Polygon) + geometry_multipoint Geometry @test.Geometry(MultiPoint) + geometry_multiline Geometry @test.Geometry(MultiLineString) + geometry_multipoly Geometry @test.Geometry(MultiPolygon) + geometry_collection Geometry @test.Geometry(GeometryCollection) }"# }; @@ -50,7 +50,7 @@ mod sqlite { geometry_collection } }"#), - @r###"{"data":{"createOneModel":{"geometry":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geometry_point":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geometry_line":"{\"type\": \"LineString\", \"coordinates\": [[1,2],[3,4]]}","geometry_poly":"{\"type\": \"Polygon\", \"coordinates\": [[[1,2],[3,4],[5,6],[1,2]]]}","geometry_multipoint":"{\"type\": \"MultiPoint\", \"coordinates\": [[1,2]]}","geometry_multiline":"{\"type\": \"MultiLineString\", \"coordinates\": [[[1,2],[3,4]]]}","geometry_multipoly":"{\"type\": \"MultiPolygon\", \"coordinates\": [[[[1,2],[3,4],[5,6],[1,2]]]]}","geometry_collection":"{\"type\": \"GeometryCollection\", \"geometries\": [{\"type\": \"Point\", \"coordinates\": [1,2]}]}"}}}"### + @r###"{"data":{"createOneModel":{"geometry":"{\"type\":\"Point\",\"coordinates\":[1,2]}","geometry_point":"{\"type\":\"Point\",\"coordinates\":[1,2]}","geometry_line":"{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}","geometry_poly":"{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}","geometry_multipoint":"{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}","geometry_multiline":"{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}","geometry_multipoly":"{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}","geometry_collection":"{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}"}}}"### ); Ok(()) @@ -101,7 +101,7 @@ mod sqlite { geometry_collection } }"#), - @r###"{"data":{"createOneModel":{"geometry":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geometry_point":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geometry_line":"{\"type\": \"LineString\", \"coordinates\": [[1,2],[3,4]]}","geometry_poly":"{\"type\": \"Polygon\", \"coordinates\": [[[1,2],[3,4],[5,6],[1,2]]]}","geometry_multipoint":"{\"type\": \"MultiPoint\", \"coordinates\": [[1,2]]}","geometry_multiline":"{\"type\": \"MultiLineString\", \"coordinates\": [[[1,2],[3,4]]]}","geometry_multipoly":"{\"type\": \"MultiPolygon\", \"coordinates\": [[[[1,2],[3,4],[5,6],[1,2]]]]}","geometry_collection":"{\"type\": \"GeometryCollection\", \"geometries\": [{\"type\": \"Point\", \"coordinates\": [1,2]}]}"}}}"### + @r###"{"data":{"createOneModel":{"geometry":"{\"type\":\"Point\",\"coordinates\":[1,2]}","geometry_point":"{\"type\":\"Point\",\"coordinates\":[1,2]}","geometry_line":"{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}","geometry_poly":"{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}","geometry_multipoint":"{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}","geometry_multiline":"{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}","geometry_multipoly":"{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}","geometry_collection":"{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}"}}}"### ); Ok(()) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs index 43d65ab3b9b3..2803475fe4fc 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs @@ -433,10 +433,9 @@ mod geometry_create { // TODO@geometry: ideally, make geojson generation consistent with SQL connectors match_connector_result!( &runner, - r#"mutation { createOneTestModel(data: { id: 1, geometry: "{\"type\": \"Point\", \"coordinates\": [1,2]}" }) { geometry }}"#, + r#"mutation { createOneTestModel(data: { id: 1, geometry: "{\"type\":\"Point\",\"coordinates\":[1,2]}" }) { geometry }}"#, // MongoDB excludes undefined fields - MongoDb(_) => vec![r#"{"data":{"createOneTestModel":{"geometry":"{\"type\":\"Point\",\"coordinates\":[1,2]}"}}}"#], - _ => vec![r#"{"data":{"createOneTestModel":{"geometry":"{\"type\": \"Point\", \"coordinates\": [1,2]}"}}}"#] + _ => vec![r#"{"data":{"createOneTestModel":{"geometry":"{\"type\":\"Point\",\"coordinates\":[1,2]}"}}}"#] ); insta::assert_snapshot!( diff --git a/query-engine/connectors/mongodb-query-connector/src/value.rs b/query-engine/connectors/mongodb-query-connector/src/value.rs index cdea4e366990..cc84d8628bac 100644 --- a/query-engine/connectors/mongodb-query-connector/src/value.rs +++ b/query-engine/connectors/mongodb-query-connector/src/value.rs @@ -398,7 +398,6 @@ fn read_scalar_value(bson: Bson, meta: &ScalarOutputMeta) -> crate::Result { - // TODO@geometry: should we do validation with crate geojson here instead ? PrismaValue::GeoJson(serde_json::to_string(&bson.into_relaxed_extjson())?) } diff --git a/query-engine/connectors/sql-query-connector/Cargo.toml b/query-engine/connectors/sql-query-connector/Cargo.toml index f9ce75f2d851..5d2e90c1276e 100644 --- a/query-engine/connectors/sql-query-connector/Cargo.toml +++ b/query-engine/connectors/sql-query-connector/Cargo.toml @@ -54,6 +54,7 @@ cuid = { git = "https://github.com/prisma/cuid-rust", branch = "wasm32-support" regex = "1.9.3" geozero = "0.10.0" quaint.workspace = true +geojson = { version = "0.24.1", default-features = false } [dev-dependencies] expect-test = "1" diff --git a/query-engine/connectors/sql-query-connector/src/geometry.rs b/query-engine/connectors/sql-query-connector/src/geometry.rs new file mode 100644 index 000000000000..0f0e358270d4 --- /dev/null +++ b/query-engine/connectors/sql-query-connector/src/geometry.rs @@ -0,0 +1,18 @@ +use serde_json::{Map, Value}; + +pub(crate) fn get_geometry_crs(geojson: &Map) -> Option<&str> { + geojson + .get("crs")? + .as_object()? + .get("properties")? + .as_object()? + .get("name")? + .as_str() +} + +pub(crate) fn trim_redundent_crs(geojson: &mut Map) { + let crs = get_geometry_crs(geojson); + if matches!(crs, Some("EPSG:4326" | "EPSG:0")) { + geojson.remove("crs"); + }; +} diff --git a/query-engine/connectors/sql-query-connector/src/lib.rs b/query-engine/connectors/sql-query-connector/src/lib.rs index 9bd6c2d7f211..9633c3764712 100644 --- a/query-engine/connectors/sql-query-connector/src/lib.rs +++ b/query-engine/connectors/sql-query-connector/src/lib.rs @@ -7,6 +7,7 @@ mod cursor_condition; mod database; mod error; mod filter; +mod geometry; mod join_utils; mod model_extensions; mod nested_aggregations; diff --git a/query-engine/connectors/sql-query-connector/src/model_extensions/column.rs b/query-engine/connectors/sql-query-connector/src/model_extensions/column.rs index 1ee4c358b0d2..f7c1e1850e0d 100644 --- a/query-engine/connectors/sql-query-connector/src/model_extensions/column.rs +++ b/query-engine/connectors/sql-query-connector/src/model_extensions/column.rs @@ -99,6 +99,7 @@ impl AsColumn for ScalarField { .native_column_type(self.native_type().map(|nt| nt.name())) .set_is_enum(self.type_identifier().is_enum()) .set_is_list(self.is_list()) + .set_is_geometry(self.type_identifier().is_geometry()) .default(quaint::ast::DefaultValue::Generated) } } diff --git a/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs b/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs index ad186b602e39..e5206fb6f3c9 100644 --- a/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs +++ b/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs @@ -1,12 +1,13 @@ -use crate::context::Context; +use crate::{context::Context, geometry::get_geometry_crs}; use chrono::Utc; -use geozero::{geojson::GeoJson, ToWkt}; +use geojson::Geometry; use prisma_value::PrismaValue; use quaint::{ - ast::{EnumName, GeometryValue, Value, ValueType}, + ast::{EnumName, Value, ValueType}, prelude::{EnumVariant, TypeDataLength, TypeFamily}, }; use query_structure::{ScalarField, TypeIdentifier}; +use serde_json::json; pub(crate) trait ScalarFieldExt { fn value<'a>(&self, pv: PrismaValue, ctx: &Context<'_>) -> Value<'a>; @@ -55,11 +56,31 @@ impl ScalarFieldExt for ScalarField { (PrismaValue::Bytes(b), _) => Value::bytes(b), (PrismaValue::Object(_), _) => unimplemented!(), (PrismaValue::GeoJson(s), _) => { - // GeoJSON string should have been validated before - let wkt = GeoJson(&s).to_wkt().unwrap(); - match self.type_family() { - TypeFamily::Geography(srid) => Value::geography(GeometryValue { wkt, srid }), - TypeFamily::Geometry(srid) => Value::geometry(GeometryValue { wkt, srid }), + let mut geometry = s.parse::().unwrap(); + let column_type = self.type_family(); + let column_srid = match column_type { + TypeFamily::Geography(srid) => srid, + TypeFamily::Geometry(srid) => srid, + _ => unreachable!(), + }; + // To facilitate geometry insertion, We manually set the GeoJSON CRS field + // to the column constrained SRID if the latter is set to 4326 (the default) + // or "unknown" (0 or -1). If there is no contraint at all, set it to 4326 + // anyway for conistency's sake, and also because SQL Server requires one + // in order to create a geometry + let geometry_crs = geometry.foreign_members.as_ref().and_then(|m| get_geometry_crs(m)); + if geometry_crs.is_none() && matches!(column_srid, None | Some(-1 | 0 | 4326)) { + let srid = column_srid.unwrap_or(4326); + let mut m = serde_json::Map::new(); + m.insert( + "crs".to_string(), + json!({"type": "name", "properties": {"name": format!("EPSG:{srid}")}}), + ); + geometry.foreign_members = Some(m); + }; + match column_type { + TypeFamily::Geography(_) => Value::geography(geometry), + TypeFamily::Geometry(_) => Value::geometry(geometry), _ => unreachable!(), } } @@ -120,7 +141,7 @@ impl ScalarFieldExt for ScalarField { let name = nt.name(); let srid = match nt.args().as_slice() { [srid] => srid.parse::().ok(), - [_, srid] => srid.parse::().ok(), + [_type, srid] => srid.parse::().ok(), _ => None, }; (name, srid) diff --git a/query-engine/connectors/sql-query-connector/src/query_builder/read.rs b/query-engine/connectors/sql-query-connector/src/query_builder/read.rs index 258c9a9e6d44..54b1571384a8 100644 --- a/query-engine/connectors/sql-query-connector/src/query_builder/read.rs +++ b/query-engine/connectors/sql-query-connector/src/query_builder/read.rs @@ -4,7 +4,6 @@ use crate::{ }; use connector_interface::AggregationSelection; use itertools::Itertools; -use psl::datamodel_connector::Connector; use quaint::ast::*; use query_structure::*; use tracing::Span; @@ -125,14 +124,6 @@ impl SelectDefinition for QueryArguments { } } -fn get_column_read_expression<'a>(col: Column<'a>, connector: &'a dyn Connector) -> Expression<'a> { - let supports_raw_geom_io = connector.supports_raw_geometry_read(); - match col.type_family { - Some(TypeFamily::Geometry(_) | TypeFamily::Geography(_)) if !supports_raw_geom_io => geom_as_text(col).into(), - _ => col.into(), - } -} - pub(crate) fn get_records<'a, T>( model: &Model, columns: impl Iterator>, @@ -144,13 +135,10 @@ where T: SelectDefinition, { let (select, additional_selection_set) = query.into_select(model, virtual_selections, ctx); - let select = columns - .map(|c| get_column_read_expression(c, model.dm.schema.connector)) - .fold(select, |acc, col| acc.value(col)); + let select = columns.fold(select, |acc, col| acc.column(col)); let select = select.append_trace(&Span::current()).add_trace_id(ctx.trace_id); - // TODO@geometry: Should we call get_column_read_expression in "additional_selection_set" too ? additional_selection_set .into_iter() .fold(select, |acc, col| acc.value(col)) @@ -200,6 +188,7 @@ pub(crate) fn aggregate( AggregationSelection::Field(field) => select.column( Column::from(field.db_name().to_owned()) .set_is_enum(field.type_identifier().is_enum()) + .set_is_geometry(field.type_identifier().is_geometry()) .set_is_selected(true), ), diff --git a/query-engine/connectors/sql-query-connector/src/query_builder/write.rs b/query-engine/connectors/sql-query-connector/src/query_builder/write.rs index 6d8e5ec42f19..c089f0834dcb 100644 --- a/query-engine/connectors/sql-query-connector/src/query_builder/write.rs +++ b/query-engine/connectors/sql-query-connector/src/query_builder/write.rs @@ -31,7 +31,6 @@ pub(crate) fn create_record( insert.value(db_name.to_owned(), field.value(value, ctx)) }); - // TODO@geometry: Should we call geom_as_text in returning statement too ? Insert::from(insert) .returning(selected_fields.as_columns(ctx).map(|c| c.set_is_selected(true))) .append_trace(&Span::current()) diff --git a/query-engine/connectors/sql-query-connector/src/row.rs b/query-engine/connectors/sql-query-connector/src/row.rs index f19545db798a..3099986a4adf 100644 --- a/query-engine/connectors/sql-query-connector/src/row.rs +++ b/query-engine/connectors/sql-query-connector/src/row.rs @@ -1,11 +1,11 @@ -use crate::{column_metadata::ColumnMetadata, error::SqlError, value::to_prisma_value}; +use crate::{column_metadata::ColumnMetadata, error::SqlError, geometry::trim_redundent_crs, value::to_prisma_value}; use bigdecimal::{BigDecimal, FromPrimitive, ToPrimitive}; use chrono::{DateTime, NaiveDate, Utc}; use connector_interface::{coerce_null_to_zero_value, AggregationResult, AggregationSelection}; -use geozero::wkt::WktStr; -use geozero::ToJson; +use geozero::{wkt::WktStr, ToJson}; use quaint::{connector::ResultRow, Value, ValueType}; use query_structure::{ConversionFailure, FieldArity, PrismaValue, Record, TypeIdentifier}; +use serde_json::json; use std::{io, str::FromStr}; use uuid::Uuid; @@ -291,22 +291,29 @@ fn row_value_to_prisma_value(p_value: Value, meta: ColumnMetadata<'_>) -> Result }, TypeIdentifier::Geometry => match p_value.typed { value if value.is_null() => PrismaValue::Null, - // MSSQL 5.6 and SQL Server cannot return geometry as GeoJSON, so for consistency's - // sake Quaint will return EWKT for all vendors. We must then serialize the EWKT - // string back to geojson. WKT can represent more spatial types than GeoJSON, so - // this operation may fail. - // For now, we'll just discard the SRID, but ideally we should include it in the - // resulting GeoJSON, in case it is different than 4326 - ValueType::Text(Some(ref ewkt)) => { - let wkt_start = if ewkt.starts_with("SRID=") { - ewkt.find(';').map(|i| i + 1).unwrap_or(0) - } else { - 0 - }; - WktStr(&ewkt[wkt_start..]) + ValueType::Json(Some(mut geojson)) => { + geojson.as_object_mut().map(trim_redundent_crs); + PrismaValue::GeoJson(geojson.to_string()) + } + ValueType::Text(Some(ref geom)) if geom.starts_with("{") => { + let mut geojson = geom.parse::()?; + geojson.as_object_mut().map(trim_redundent_crs); + PrismaValue::GeoJson(geojson.to_string()) + } + ValueType::Text(Some(ref geom)) => { + // SQlite and Postgres return GeoJSON as strings. SQL Server cannot return geometry as GeoJSON, + // and return an EWKT string instead. We differentiate the two by checking the first character. + let (srid, wkt) = geom.split_once(";").unwrap(); + let srid = &srid[5..]; + let mut geojson = WktStr(wkt) .to_json() - .map(PrismaValue::GeoJson) .map_err(|_| create_error(&p_value))? + .parse::()?; + if !matches!(srid, "0" | "4326") { + let crs = json!({"type": "name", "properties": {"name": format!("EPSG:{srid}")}}); + geojson.as_object_mut().map(|g| g.insert("crs".to_string(), crs)); + } + PrismaValue::GeoJson(geojson.to_string()) } _ => return Err(create_error(&p_value)), }, diff --git a/query-engine/query-structure/src/field/mod.rs b/query-engine/query-structure/src/field/mod.rs index fc3e718dfde2..d4e989d99a55 100644 --- a/query-engine/query-structure/src/field/mod.rs +++ b/query-engine/query-structure/src/field/mod.rs @@ -190,6 +190,11 @@ impl TypeIdentifier { pub fn is_json(&self) -> bool { matches!(self, Self::Json) } + + /// Returns `true` if the type identifier is [`Geometry`]. + pub fn is_geometry(&self) -> bool { + matches!(self, Self::Geometry) + } } #[derive(Clone, Debug, PartialEq, Eq, Hash)] diff --git a/query-engine/query-structure/src/field/scalar.rs b/query-engine/query-structure/src/field/scalar.rs index 0ab0ad322651..119511d10fed 100644 --- a/query-engine/query-structure/src/field/scalar.rs +++ b/query-engine/query-structure/src/field/scalar.rs @@ -64,7 +64,7 @@ impl ScalarField { } pub fn is_geometry(&self) -> bool { - matches!(self.type_identifier(), TypeIdentifier::Geometry) + self.type_identifier().is_geometry() } pub fn container(&self) -> ParentContainer { diff --git a/schema-engine/connectors/sql-schema-connector/src/sql_renderer/postgres_renderer.rs b/schema-engine/connectors/sql-schema-connector/src/sql_renderer/postgres_renderer.rs index 121255b11fb4..2037826b21d1 100644 --- a/schema-engine/connectors/sql-schema-connector/src/sql_renderer/postgres_renderer.rs +++ b/schema-engine/connectors/sql-schema-connector/src/sql_renderer/postgres_renderer.rs @@ -658,7 +658,6 @@ fn render_decimal_args(input: Option<(u32, u32)>) -> String { fn render_geometry_arg(input: Option) -> String { match input { None => "".to_string(), - Some(GeometryParams { type_, srid: 0 }) => format!("({type_})"), Some(GeometryParams { type_, srid }) => format!("({type_}, {srid})"), } } 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 eececda75f8a..5429481258c3 100644 --- a/schema-engine/sql-introspection-tests/tests/native_types/postgres.rs +++ b/schema-engine/sql-introspection-tests/tests/native_types/postgres.rs @@ -161,21 +161,21 @@ async fn native_type_spatial_columns_feature_on(api: &mut TestApi) -> TestResult id Int @id geometry Geometry geometry_srid Geometry @db.Geometry(Geometry, 3857) - geometry_geometry_z Geometry @db.Geometry(GeometryZ) - geometry_point Geometry @db.Geometry(Point) - geometry_point_z Geometry @db.Geometry(PointZ) - geometry_linestring Geometry @db.Geometry(LineString) - geometry_linestring_z Geometry @db.Geometry(LineStringZ) - geometry_polygon Geometry @db.Geometry(Polygon) - geometry_polygon_z Geometry @db.Geometry(PolygonZ) - geometry_multipoint Geometry @db.Geometry(MultiPoint) - geometry_multipoint_z Geometry @db.Geometry(MultiPointZ) - geometry_multilinestring Geometry @db.Geometry(MultiLineString) - geometry_multilinestring_z Geometry @db.Geometry(MultiLineStringZ) - geometry_multipolygon Geometry @db.Geometry(MultiPolygon) - geometry_multipolygon_z Geometry @db.Geometry(MultiPolygonZ) - geometry_geometrycollection Geometry @db.Geometry(GeometryCollection) - geometry_geometrycollection_z Geometry @db.Geometry(GeometryCollectionZ) + geometry_geometry_z Geometry @db.Geometry(GeometryZ, 0) + geometry_point Geometry @db.Geometry(Point, 0) + geometry_point_z Geometry @db.Geometry(PointZ, 0) + geometry_linestring Geometry @db.Geometry(LineString, 0) + geometry_linestring_z Geometry @db.Geometry(LineStringZ, 0) + geometry_polygon Geometry @db.Geometry(Polygon, 0) + geometry_polygon_z Geometry @db.Geometry(PolygonZ, 0) + geometry_multipoint Geometry @db.Geometry(MultiPoint, 0) + geometry_multipoint_z Geometry @db.Geometry(MultiPointZ, 0) + geometry_multilinestring Geometry @db.Geometry(MultiLineString, 0) + geometry_multilinestring_z Geometry @db.Geometry(MultiLineStringZ, 0) + geometry_multipolygon Geometry @db.Geometry(MultiPolygon, 0) + geometry_multipolygon_z Geometry @db.Geometry(MultiPolygonZ, 0) + geometry_geometrycollection Geometry @db.Geometry(GeometryCollection, 0) + geometry_geometrycollection_z Geometry @db.Geometry(GeometryCollectionZ, 0) geography_geometry Geometry @db.Geography(Geometry, 4326) geography_geometry_z Geometry @db.Geography(GeometryZ, 4326) geography_point Geometry @db.Geography(Point, 4326) From 984f9dcbc0ae2f693858f79c5c45977d06aee638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Sat, 5 Oct 2024 13:04:35 +0200 Subject: [PATCH 065/103] Skip geometry tests on MySQL(5.6). and fix tests --- quaint/src/visitor.rs | 2 +- quaint/src/visitor/mssql.rs | 20 ++++++++++++------- quaint/src/visitor/mysql.rs | 19 +++--------------- quaint/src/visitor/postgres.rs | 19 +++--------------- quaint/src/visitor/sqlite.rs | 19 +++--------------- .../tests/queries/filters/geometry_filter.rs | 12 ++++++++--- .../tests/raw/sql/typed_output.rs | 4 ++-- .../writes/data_types/native_types/mysql.rs | 2 +- .../writes/top_level_mutations/create.rs | 3 ++- 9 files changed, 37 insertions(+), 63 deletions(-) diff --git a/quaint/src/visitor.rs b/quaint/src/visitor.rs index e3e9908ac319..34e31856bdeb 100644 --- a/quaint/src/visitor.rs +++ b/quaint/src/visitor.rs @@ -240,7 +240,7 @@ pub trait Visitor<'a> { ValueType::EnumArray(Some(variants), name) => self.visit_parameterized_enum_array(variants, name), ValueType::Text(txt) => self.visit_parameterized_text(txt, value.native_column_type), ValueType::Geometry(Some(geometry)) => self.visit_parameterized_geometry(geometry), - ValueType::Geography(Some(geometry)) => self.visit_parameterized_geometry(geometry), + ValueType::Geography(Some(geography)) => self.visit_parameterized_geography(geography), ValueType::Geometry(None) | ValueType::Geography(None) => self.write("NULL"), _ => { self.add_parameter(value); diff --git a/quaint/src/visitor/mssql.rs b/quaint/src/visitor/mssql.rs index c71384ffe1d8..bfee8ab9607a 100644 --- a/quaint/src/visitor/mssql.rs +++ b/quaint/src/visitor/mssql.rs @@ -22,7 +22,7 @@ pub struct Mssql<'a> { order_by_set: bool, } -fn get_geometry_srid(geom: &geojson::Geometry) -> Option { +fn get_geojson_srid(geom: &geojson::Geometry) -> Option { geom.foreign_members .as_ref()? .get("crs")? @@ -37,8 +37,8 @@ fn get_geometry_srid(geom: &geojson::Geometry) -> Option { .ok() } -fn geojson_to_wkt_srid(geometry: &geojson::Geometry) -> crate::Result<(String, i32)> { - let srid = get_geometry_srid(geometry) +fn get_wkt_srid_from_geojson(geometry: &geojson::Geometry) -> crate::Result<(String, i32)> { + let srid = get_geojson_srid(geometry) .ok_or_else(|| Error::builder(ErrorKind::QueryInvalidInput("Invalid SRID in GeoJSON CRS".into())).build())?; let wkt = geozero::geojson::GeoJsonString(geometry.to_string()).to_wkt()?; Ok((wkt, srid)) @@ -278,12 +278,12 @@ impl<'a> Visitor<'a> for Mssql<'a> { } fn visit_parameterized_geometry(&mut self, geometry: geojson::Geometry) -> visitor::Result { - let (wkt, srid) = geojson_to_wkt_srid(&geometry)?; + let (wkt, srid) = get_wkt_srid_from_geojson(&geometry)?; self.visit_function(geom_from_text(wkt, Some(srid), false)) } fn visit_parameterized_geography(&mut self, geometry: geojson::Geometry) -> visitor::Result { - let (wkt, srid) = geojson_to_wkt_srid(&geometry)?; + let (wkt, srid) = get_wkt_srid_from_geojson(&geometry)?; self.visit_function(geom_from_text(wkt, Some(srid), true)) } @@ -455,8 +455,14 @@ impl<'a> Visitor<'a> for Mssql<'a> { // Style 3 is keep all whitespace + internal DTD processing: // https://docs.microsoft.com/en-us/sql/t-sql/functions/cast-and-convert-transact-sql?redirectedfrom=MSDN&view=sql-server-ver15#xml-styles ValueType::Xml(cow) => cow.map(|cow| self.write(format!("CONVERT(XML, N'{cow}', 3)"))), - ValueType::Geometry(geojson) => geojson.map(|g| self.visit_function(geom_from_geojson(g.to_string()))), - ValueType::Geography(geojson) => geojson.map(|g| self.visit_function(geom_from_geojson(g.to_string()))), + ValueType::Geometry(geojson) => geojson.map(|g| { + let (wkt, srid) = get_wkt_srid_from_geojson(&g)?; + self.visit_function(geom_from_text(wkt.raw(), Some(srid.raw()), false)) + }), + ValueType::Geography(geojson) => geojson.map(|g| { + let (wkt, srid) = get_wkt_srid_from_geojson(&g)?; + self.visit_function(geom_from_text(wkt.raw(), Some(srid.raw()), false)) + }), }; match res { diff --git a/quaint/src/visitor/mysql.rs b/quaint/src/visitor/mysql.rs index 4f36b094e727..a9b00183cf4d 100644 --- a/quaint/src/visitor/mysql.rs +++ b/quaint/src/visitor/mysql.rs @@ -932,23 +932,10 @@ mod tests { #[test] fn test_raw_geometry() { - let geom = r#"{"type": "Point", "coordinates": [1, 2]}"#.parse::().unwrap(); + let geojson = r#"{"type":"Point","coordinates":[1.0,2.0]}"#; + let geom = geojson.parse::().unwrap(); let (sql, params) = Mysql::build(Select::default().value(Value::geometry(geom).raw())).unwrap(); - assert_eq!( - r#"SELECT ST_GeomFromGeoJSON('{"type":"Point","coordinates":[1,2]}')"#, - sql - ); - assert!(params.is_empty()); - } - - #[test] - fn test_raw_geography() { - let geom = r#"{"type": "Point", "coordinates": [1, 2]}"#.parse::().unwrap(); - let (sql, params) = Mysql::build(Select::default().value(Value::geography(geom).raw())).unwrap(); - assert_eq!( - r#"SELECT ST_GeomFromGeoJSON('{"type":"Point","coordinates":[1,2]}')"#, - sql - ); + assert_eq!(format!("SELECT ST_GeomFromGeoJSON('{geojson}')"), sql); assert!(params.is_empty()); } diff --git a/quaint/src/visitor/postgres.rs b/quaint/src/visitor/postgres.rs index aab7ef97514d..dd32af86b4c6 100644 --- a/quaint/src/visitor/postgres.rs +++ b/quaint/src/visitor/postgres.rs @@ -1235,23 +1235,10 @@ mod tests { #[test] fn test_raw_geometry() { - let geom = r#"{"type": "Point", "coordinates": [1, 2]}"#.parse::().unwrap(); + let geojson = r#"{"type":"Point","coordinates":[1.0,2.0]}"#; + let geom = geojson.parse::().unwrap(); let (sql, params) = Postgres::build(Select::default().value(Value::geometry(geom).raw())).unwrap(); - assert_eq!( - r#"SELECT ST_GeomFromGeoJSON('{"type":"Point","coordinates":[1,2]}')"#, - sql - ); - assert!(params.is_empty()); - } - - #[test] - fn test_raw_geography() { - let geom = r#"{"type": "Point", "coordinates": [1, 2]}"#.parse::().unwrap(); - let (sql, params) = Postgres::build(Select::default().value(Value::geography(geom).raw())).unwrap(); - assert_eq!( - r#"SELECT ST_GeomFromGeoJSON('{"type":"Point","coordinates":[1,2]}')"#, - sql - ); + assert_eq!(format!("SELECT ST_GeomFromGeoJSON('{geojson}')"), sql); assert!(params.is_empty()); } diff --git a/quaint/src/visitor/sqlite.rs b/quaint/src/visitor/sqlite.rs index 93be01f549f2..b875cb28aa33 100644 --- a/quaint/src/visitor/sqlite.rs +++ b/quaint/src/visitor/sqlite.rs @@ -1076,23 +1076,10 @@ mod tests { #[test] fn test_raw_geometry() { - let geom = r#"{"type": "Point", "coordinates": [1, 2]}"#.parse::().unwrap(); + let geojson = r#"{"type":"Point","coordinates":[1.0,2.0]}"#; + let geom = geojson.parse::().unwrap(); let (sql, params) = Sqlite::build(Select::default().value(Value::geometry(geom).raw())).unwrap(); - assert_eq!( - r#"SELECT ST_GeomFromGeoJSON('{"type":"Point","coordinates":[1,2]}')"#, - sql - ); - assert!(params.is_empty()); - } - - #[test] - fn test_raw_geography() { - let geom = r#"{"type": "Point", "coordinates": [1, 2]}"#.parse::().unwrap(); - let (sql, params) = Sqlite::build(Select::default().value(Value::geography(geom).raw())).unwrap(); - assert_eq!( - r#"SELECT ST_GeomFromGeoJSON('{"type":"Point","coordinates":[1,2]}')"#, - sql - ); + assert_eq!(format!("SELECT GeomFromGeoJSON('{geojson}')"), sql); assert!(params.is_empty()); } diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs index ae8f3c8aaf4c..0c06ea6eb333 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs @@ -101,12 +101,18 @@ mod geometry_filter_spec { Ok(()) } - #[connector_test(schema(schema), exclude(Postgres, Sqlite(3, "cfd1", "libsql.js", "libsql.js.wasm")))] + #[connector_test( + schema(schema), + exclude(Postgres, MySql(5.6), Sqlite(3, "cfd1", "libsql.js", "libsql.js.wasm")) + )] async fn basic_where(runner: Runner) -> TestResult<()> { basic_where_test(runner).await } - #[connector_test(schema(schema), exclude(Postgres, Sqlite(3, "cfd1", "libsql.js", "libsql.js.wasm")))] + #[connector_test( + schema(schema), + exclude(Postgres, MySql(5.6), Sqlite(3, "cfd1", "libsql.js", "libsql.js.wasm")) + )] async fn where_shorthands(runner: Runner) -> TestResult<()> { where_shorthands_test(runner).await } @@ -115,7 +121,7 @@ mod geometry_filter_spec { // see discussion here: https://github.com/prisma/prisma-engines/pull/4208#issuecomment-1828997865 #[connector_test( schema(schema), - exclude(Postgres, Sqlite(3, "cfd1", "libsql.js", "libsql.js.wasm"), MySQL("mariadb")), + exclude(Postgres, Sqlite(3, "cfd1", "libsql.js", "libsql.js.wasm"), MySQL("mariadb", 5.6)), capabilities(GeometryFiltering) )] async fn geometric_comparison_filters(runner: Runner) -> TestResult<()> { diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/raw/sql/typed_output.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/raw/sql/typed_output.rs index 6edda2a7d396..73b4f5c73a7c 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/raw/sql/typed_output.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/raw/sql/typed_output.rs @@ -441,10 +441,10 @@ mod typed_output { } #[connector_test(schema(generic), only(Mysql))] - async fn geometry_type_mysql(runner: Runner) -> TestResult<()> { + async fn unknown_type_mysql(runner: Runner) -> TestResult<()> { insta::assert_snapshot!( run_query!(&runner, fmt_query_raw(r#"SELECT POINT(1, 1);"#, vec![])), - @r###"{"data":{"queryRaw":{"columns":["POINT(1, 1)"],"types":["geometry"],"rows":[["POINT(1 1)"]]}}}"### + @r###"{"data":{"queryRaw":{"columns":["POINT(1, 1)"],"types":["geometry"],"rows":[["AAAAAAEBAAAAAAAAAAAA8D8AAAAAAADwPw=="]]}}}"### ); Ok(()) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs index 72455f999831..7098a29d1ee0 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs @@ -450,7 +450,7 @@ mod mysql { } // "MySQL native spatial types" should "work" - #[connector_test(schema(schema_geometry_types))] + #[connector_test(exclude(MySQL(5.6)), schema(schema_geometry_types))] async fn native_geometry_types(runner: Runner) -> TestResult<()> { insta::assert_snapshot!( run_query!(&runner, r#"mutation { diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs index 2803475fe4fc..6ffb23d8eeea 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs @@ -435,6 +435,7 @@ mod geometry_create { &runner, r#"mutation { createOneTestModel(data: { id: 1, geometry: "{\"type\":\"Point\",\"coordinates\":[1,2]}" }) { geometry }}"#, // MongoDB excludes undefined fields + MySql(_) => vec![r#"{"data":{"createOneTestModel":{"geometry":"{\"coordinates\":[1,2],\"type\":\"Point\"}"}}}"#], _ => vec![r#"{"data":{"createOneTestModel":{"geometry":"{\"type\":\"Point\",\"coordinates\":[1,2]}"}}}"#] ); @@ -476,7 +477,7 @@ mod geometry_create { #[connector_test( schema(geometry_opt), - exclude(Postgres, Sqlite(3, "cfd1", "libsql.js", "libsql.js.wasm")) + exclude(Postgres, MySQL(5.6), Sqlite(3, "cfd1", "libsql.js", "libsql.js.wasm")) )] async fn create_geometry(runner: Runner) -> TestResult<()> { create_geometry_test(runner).await From 6bb32fed858d6e812b1fb18a37ccdcf5bb0ec1ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Sat, 5 Oct 2024 17:14:55 +0200 Subject: [PATCH 066/103] Fix more tests --- quaint/src/visitor/mssql.rs | 3 +- .../writes/data_types/native_types/mysql.rs | 34 ++++++++++--------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/quaint/src/visitor/mssql.rs b/quaint/src/visitor/mssql.rs index bfee8ab9607a..5cbf9342e7ac 100644 --- a/quaint/src/visitor/mssql.rs +++ b/quaint/src/visitor/mssql.rs @@ -38,8 +38,7 @@ fn get_geojson_srid(geom: &geojson::Geometry) -> Option { } fn get_wkt_srid_from_geojson(geometry: &geojson::Geometry) -> crate::Result<(String, i32)> { - let srid = get_geojson_srid(geometry) - .ok_or_else(|| Error::builder(ErrorKind::QueryInvalidInput("Invalid SRID in GeoJSON CRS".into())).build())?; + let srid = get_geojson_srid(geometry).unwrap_or(4326); let wkt = geozero::geojson::GeoJsonString(geometry.to_string()).to_wkt()?; Ok((wkt, srid)) } diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs index 7098a29d1ee0..30a0bd4efbfa 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs @@ -450,10 +450,11 @@ mod mysql { } // "MySQL native spatial types" should "work" - #[connector_test(exclude(MySQL(5.6)), schema(schema_geometry_types))] + #[connector_test(only(MySQL(5.7, 8, "mariadb")), schema(schema_geometry_types))] async fn native_geometry_types(runner: Runner) -> TestResult<()> { - insta::assert_snapshot!( - run_query!(&runner, r#"mutation { + match_connector_result!( + &runner, + r#"mutation { createOneModel( data: { geometry: "{\"type\":\"Point\",\"coordinates\" :[1,2]}" @@ -475,11 +476,12 @@ mod mysql { multipoly collection } - }"#), - @r###"{"data":{"createOneModel":{"geometry":"{\"coordinates\":[1,2],\"type\":\"Point\"}","point":"{\"coordinates\":[1,2],\"type\":\"Point\"}","line":"{\"coordinates\":[[1,2],[3,4]],\"type\":\"LineString\"}","poly":"{\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]],\"type\":\"Polygon\"}","multipoint":"{\"coordinates\":[[1,2]],\"type\":\"MultiPoint\"}","multiline":"{\"coordinates\":[[[1,2],[3,4]]],\"type\":\"MultiLineString\"}","multipoly":"{\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]],\"type\":\"MultiPolygon\"}","collection":"{\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}],\"type\":\"GeometryCollection\"}"}}}"### - ); + }"#, + MySql(Some(MySqlVersion::V8)) => r###"{"data":{"createOneModel":{"geometry":"{\"coordinates\":[1.0,2.0],\"type\":\"Point\"}","point":"{\"coordinates\":[1.0,2.0],\"type\":\"Point\"}","line":"{\"coordinates\":[[1.0,2.0],[3.0,4.0]],\"type\":\"LineString\"}","poly":"{\"coordinates\":[[[1.0,2.0],[3.0,4.0],[5.0,6.0],[1.0,2.0]]],\"type\":\"Polygon\"}","multipoint":"{\"coordinates\":[[1.0,2.0]],\"type\":\"MultiPoint\"}","multiline":"{\"coordinates\":[[[1.0,2.0],[3.0,4.0]]],\"type\":\"MultiLineString\"}","multipoly":"{\"coordinates\":[[[[1.0,2.0],[3.0,4.0],[5.0,6.0],[1.0,2.0]]]],\"type\":\"MultiPolygon\"}","collection":"{\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1.0,2.0]}],\"type\":\"GeometryCollection\"}"}}}"###, + _ => r###"{"data":{"createOneModel":{"geometry":"{\"coordinates\":[1,2],\"type\":\"Point\"}","point":"{\"coordinates\":[1,2],\"type\":\"Point\"}","line":"{\"coordinates\":[[1,2],[3,4]],\"type\":\"LineString\"}","poly":"{\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]],\"type\":\"Polygon\"}","multipoint":"{\"coordinates\":[[1,2]],\"type\":\"MultiPoint\"}","multiline":"{\"coordinates\":[[[1,2],[3,4]]],\"type\":\"MultiLineString\"}","multipoly":"{\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]],\"type\":\"MultiPolygon\"}","collection":"{\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}],\"type\":\"GeometryCollection\"}"}}}"### + ); - Ok(()) + Ok(()) } fn schema_geometry_srid_types() -> String { @@ -507,14 +509,14 @@ mod mysql { run_query!(&runner, r#"mutation { createOneModel( data: { - geometry: "{\"type\":\"Point\",\"coordinates\" :[1,2]}" - point: "{\"type\":\"Point\",\"coordinates\" :[1,2]}" - line: "{\"type\":\"LineString\",\"coordinates\" :[[1,2],[3,4]]}" - poly: "{\"type\":\"Polygon\",\"coordinates\" :[[[1,2],[3,4],[5,6],[1,2]]]}" - multipoint: "{\"type\":\"MultiPoint\",\"coordinates\" :[[1,2]]}" - multiline: "{\"type\":\"MultiLineString\",\"coordinates\" :[[[1,2],[3,4]]]}" - multipoly: "{\"type\":\"MultiPolygon\",\"coordinates\" :[[[[1,2],[3,4],[5,6],[1,2]]]]}" - collection: "{\"type\":\"GeometryCollection\",\"geometries\" :[{\"type\":\"Point\",\"coordinates\" :[1,2]}]}" + geometry: "{\"type\":\"Point\",\"coordinates\" :[1,2],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}}}" + point: "{\"type\":\"Point\",\"coordinates\" :[1,2],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}}}" + line: "{\"type\":\"LineString\",\"coordinates\" :[[1,2],[3,4]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}}}" + poly: "{\"type\":\"Polygon\",\"coordinates\" :[[[1,2],[3,4],[5,6],[1,2]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}}}" + multipoint: "{\"type\":\"MultiPoint\",\"coordinates\" :[[1,2]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}}}" + multiline: "{\"type\":\"MultiLineString\",\"coordinates\" :[[[1,2],[3,4]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}}}" + multipoly: "{\"type\":\"MultiPolygon\",\"coordinates\" :[[[[1,2],[3,4],[5,6],[1,2]]]],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}}}" + collection: "{\"type\":\"GeometryCollection\",\"geometries\" :[{\"type\":\"Point\",\"coordinates\" :[1,2]}],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}}}" } ) { geometry, @@ -527,7 +529,7 @@ mod mysql { collection } }"#), - @r###"{"data":{"createOneModel":{"geometry":"{\"type\":\"Point\",\"coordinates\":[1,2]}","point":"{\"type\":\"Point\",\"coordinates\":[1,2]}","line":"{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}","poly":"{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}","multipoint":"{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}","multiline":"{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}","multipoly":"{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}","collection":"{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}"}}}"### + @r###"{"data":{"createOneModel":{"geometry":"{\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}},\"type\":\"Point\",\"coordinates\":[1.0,2.0]}","point":"{\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}},\"type\":\"Point\",\"coordinates\":[1.0,2.0]}","line":"{\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}},\"type\":\"LineString\",\"coordinates\":[[1.0,2.0],[3.0,4.0]]}","poly":"{\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}},\"type\":\"Polygon\",\"coordinates\":[[[1.0,2.0],[3.0,4.0],[5.0,6.0],[1.0,2.0]]]}","multipoint":"{\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}},\"type\":\"MultiPoint\",\"coordinates\":[[1.0,2.0]]}","multiline":"{\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}},\"type\":\"MultiLineString\",\"coordinates\":[[[1.0,2.0],[3.0,4.0]]]}","multipoly":"{\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}},\"type\":\"MultiPolygon\",\"coordinates\":[[[[1.0,2.0],[3.0,4.0],[5.0,6.0],[1.0,2.0]]]]}","collection":"{\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:3857\"}},\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1.0,2.0]}]}"}}}"### ); Ok(()) From 6a95e068170660d8b4d9309b39fd87246d551dfd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Sat, 5 Oct 2024 17:45:48 +0200 Subject: [PATCH 067/103] Fix more tests --- quaint/src/visitor/mssql.rs | 4 ++-- .../tests/queries/filters/geometry_filter.rs | 4 +--- .../tests/writes/top_level_mutations/create.rs | 3 ++- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/quaint/src/visitor/mssql.rs b/quaint/src/visitor/mssql.rs index 5cbf9342e7ac..e70932d4b1e3 100644 --- a/quaint/src/visitor/mssql.rs +++ b/quaint/src/visitor/mssql.rs @@ -460,7 +460,7 @@ impl<'a> Visitor<'a> for Mssql<'a> { }), ValueType::Geography(geojson) => geojson.map(|g| { let (wkt, srid) = get_wkt_srid_from_geojson(&g)?; - self.visit_function(geom_from_text(wkt.raw(), Some(srid.raw()), false)) + self.visit_function(geom_from_text(wkt.raw(), Some(srid.raw()), true)) }), }; @@ -1469,7 +1469,7 @@ mod tests { fn test_raw_geometry() { let geom = r#"{"type": "Point", "coordinates": [1, 2]}"#.parse::().unwrap(); let (sql, params) = Mssql::build(Select::default().value(Value::geometry(geom).raw())).unwrap(); - assert_eq!("SELECT geometry::STGeomFromText('POINT(1 2)',0)", sql); + assert_eq!("SELECT geometry::STGeomFromText('POINT(1 2)',4326)", sql); assert!(params.is_empty()); } diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs index 0c06ea6eb333..aab9b008eebd 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs @@ -117,11 +117,9 @@ mod geometry_filter_spec { where_shorthands_test(runner).await } - // This test should work for MariaDB but doesn't so we skip it for now, - // see discussion here: https://github.com/prisma/prisma-engines/pull/4208#issuecomment-1828997865 #[connector_test( schema(schema), - exclude(Postgres, Sqlite(3, "cfd1", "libsql.js", "libsql.js.wasm"), MySQL("mariadb", 5.6)), + exclude(Postgres, Sqlite(3, "cfd1", "libsql.js", "libsql.js.wasm"), MySQL(5.6)), capabilities(GeometryFiltering) )] async fn geometric_comparison_filters(runner: Runner) -> TestResult<()> { diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs index 6ffb23d8eeea..cfbe7969a6d4 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs @@ -435,7 +435,8 @@ mod geometry_create { &runner, r#"mutation { createOneTestModel(data: { id: 1, geometry: "{\"type\":\"Point\",\"coordinates\":[1,2]}" }) { geometry }}"#, // MongoDB excludes undefined fields - MySql(_) => vec![r#"{"data":{"createOneTestModel":{"geometry":"{\"coordinates\":[1,2],\"type\":\"Point\"}"}}}"#], + MySql(Some(MySqlVersion::V8)) => vec![r#"{"data":{"createOneTestModel":{"geometry":"{\"coordinates\":[1.0,2.0],\"type\":\"Point\"}"}}}"#], + MySql(Some(MySqlVersion::V5_7)) => vec![r#"{"data":{"createOneTestModel":{"geometry":"{\"coordinates\":[1,2],\"type\":\"Point\"}"}}}"#], _ => vec![r#"{"data":{"createOneTestModel":{"geometry":"{\"type\":\"Point\",\"coordinates\":[1,2]}"}}}"#] ); From 424671a498fb39c21abe9c04e36e257736330196 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Sat, 5 Oct 2024 17:50:12 +0200 Subject: [PATCH 068/103] Fix fmt --- .../tests/writes/data_types/native_types/mysql.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs index 30a0bd4efbfa..c97424f46178 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs @@ -452,9 +452,9 @@ mod mysql { // "MySQL native spatial types" should "work" #[connector_test(only(MySQL(5.7, 8, "mariadb")), schema(schema_geometry_types))] async fn native_geometry_types(runner: Runner) -> TestResult<()> { - match_connector_result!( - &runner, - r#"mutation { + match_connector_result!( + &runner, + r#"mutation { createOneModel( data: { geometry: "{\"type\":\"Point\",\"coordinates\" :[1,2]}" @@ -477,11 +477,11 @@ mod mysql { collection } }"#, - MySql(Some(MySqlVersion::V8)) => r###"{"data":{"createOneModel":{"geometry":"{\"coordinates\":[1.0,2.0],\"type\":\"Point\"}","point":"{\"coordinates\":[1.0,2.0],\"type\":\"Point\"}","line":"{\"coordinates\":[[1.0,2.0],[3.0,4.0]],\"type\":\"LineString\"}","poly":"{\"coordinates\":[[[1.0,2.0],[3.0,4.0],[5.0,6.0],[1.0,2.0]]],\"type\":\"Polygon\"}","multipoint":"{\"coordinates\":[[1.0,2.0]],\"type\":\"MultiPoint\"}","multiline":"{\"coordinates\":[[[1.0,2.0],[3.0,4.0]]],\"type\":\"MultiLineString\"}","multipoly":"{\"coordinates\":[[[[1.0,2.0],[3.0,4.0],[5.0,6.0],[1.0,2.0]]]],\"type\":\"MultiPolygon\"}","collection":"{\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1.0,2.0]}],\"type\":\"GeometryCollection\"}"}}}"###, - _ => r###"{"data":{"createOneModel":{"geometry":"{\"coordinates\":[1,2],\"type\":\"Point\"}","point":"{\"coordinates\":[1,2],\"type\":\"Point\"}","line":"{\"coordinates\":[[1,2],[3,4]],\"type\":\"LineString\"}","poly":"{\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]],\"type\":\"Polygon\"}","multipoint":"{\"coordinates\":[[1,2]],\"type\":\"MultiPoint\"}","multiline":"{\"coordinates\":[[[1,2],[3,4]]],\"type\":\"MultiLineString\"}","multipoly":"{\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]],\"type\":\"MultiPolygon\"}","collection":"{\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}],\"type\":\"GeometryCollection\"}"}}}"### - ); + MySql(Some(MySqlVersion::V8)) => r###"{"data":{"createOneModel":{"geometry":"{\"coordinates\":[1.0,2.0],\"type\":\"Point\"}","point":"{\"coordinates\":[1.0,2.0],\"type\":\"Point\"}","line":"{\"coordinates\":[[1.0,2.0],[3.0,4.0]],\"type\":\"LineString\"}","poly":"{\"coordinates\":[[[1.0,2.0],[3.0,4.0],[5.0,6.0],[1.0,2.0]]],\"type\":\"Polygon\"}","multipoint":"{\"coordinates\":[[1.0,2.0]],\"type\":\"MultiPoint\"}","multiline":"{\"coordinates\":[[[1.0,2.0],[3.0,4.0]]],\"type\":\"MultiLineString\"}","multipoly":"{\"coordinates\":[[[[1.0,2.0],[3.0,4.0],[5.0,6.0],[1.0,2.0]]]],\"type\":\"MultiPolygon\"}","collection":"{\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1.0,2.0]}],\"type\":\"GeometryCollection\"}"}}}"###, + _ => r###"{"data":{"createOneModel":{"geometry":"{\"coordinates\":[1,2],\"type\":\"Point\"}","point":"{\"coordinates\":[1,2],\"type\":\"Point\"}","line":"{\"coordinates\":[[1,2],[3,4]],\"type\":\"LineString\"}","poly":"{\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]],\"type\":\"Polygon\"}","multipoint":"{\"coordinates\":[[1,2]],\"type\":\"MultiPoint\"}","multiline":"{\"coordinates\":[[[1,2],[3,4]]],\"type\":\"MultiLineString\"}","multipoly":"{\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]],\"type\":\"MultiPolygon\"}","collection":"{\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}],\"type\":\"GeometryCollection\"}"}}}"### + ); - Ok(()) + Ok(()) } fn schema_geometry_srid_types() -> String { From 7b24702f32714131c0a5e99bfc1808f693b25412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Sun, 6 Oct 2024 21:56:16 +0200 Subject: [PATCH 069/103] Refactor geometry handling in quaint visitors --- quaint/src/ast/column.rs | 8 ++ quaint/src/ast/expression.rs | 1 - quaint/src/ast/function.rs | 23 --- quaint/src/ast/function/geom_as_geojson.rs | 31 ---- quaint/src/ast/function/geom_as_text.rs | 31 ---- quaint/src/ast/function/geom_from_geojson.rs | 35 ----- quaint/src/ast/function/geom_from_text.rs | 41 ------ quaint/src/geometry.rs | 14 ++ quaint/src/lib.rs | 2 + quaint/src/visitor.rs | 78 +++------- quaint/src/visitor/mssql.rs | 70 ++++----- quaint/src/visitor/mysql.rs | 51 +++---- quaint/src/visitor/postgres.rs | 136 ++++++++++++------ quaint/src/visitor/sqlite.rs | 43 +++--- .../writes/data_types/native_types/mysql.rs | 4 +- .../data_types/native_types/postgres.rs | 10 +- .../writes/top_level_mutations/create.rs | 2 +- .../src/model_extensions/scalar_field.rs | 2 +- 18 files changed, 210 insertions(+), 372 deletions(-) delete mode 100644 quaint/src/ast/function/geom_as_geojson.rs delete mode 100644 quaint/src/ast/function/geom_as_text.rs delete mode 100644 quaint/src/ast/function/geom_from_geojson.rs delete mode 100644 quaint/src/ast/function/geom_from_text.rs create mode 100644 quaint/src/geometry.rs diff --git a/quaint/src/ast/column.rs b/quaint/src/ast/column.rs index ee3276d9657e..022548c4e43f 100644 --- a/quaint/src/ast/column.rs +++ b/quaint/src/ast/column.rs @@ -86,6 +86,14 @@ impl<'a> Column<'a> { } } + pub(crate) fn into_bare_with_table(self) -> Self { + Self { + name: self.name, + table: self.table, + ..Default::default() + } + } + /// Sets the default value for the column. pub fn default(mut self, value: V) -> Self where diff --git a/quaint/src/ast/expression.rs b/quaint/src/ast/expression.rs index 34de5741b6bc..31ad1f8a21eb 100644 --- a/quaint/src/ast/expression.rs +++ b/quaint/src/ast/expression.rs @@ -258,7 +258,6 @@ impl<'a> ExpressionKind<'a> { .. })) => true, Self::Column(c) if c.is_geometry => true, - Self::Function(f) => f.returns_geometry(), Self::Value(expr) => expr.is_geometry_expr(), _ => false, } diff --git a/quaint/src/ast/function.rs b/quaint/src/ast/function.rs index 20adf494292d..82a86f773d2d 100644 --- a/quaint/src/ast/function.rs +++ b/quaint/src/ast/function.rs @@ -17,11 +17,6 @@ mod search; mod sum; mod upper; -mod geom_as_geojson; -mod geom_as_text; -mod geom_from_geojson; -mod geom_from_text; - mod uuid; pub use aggregate_to_string::*; @@ -43,11 +38,6 @@ pub use search::*; pub use sum::*; pub use upper::*; -pub use geom_as_geojson::*; -pub use geom_as_text::*; -pub use geom_from_geojson::*; -pub use geom_from_text::*; - pub use self::uuid::*; use super::{Aliasable, Expression}; @@ -70,12 +60,6 @@ impl<'a> Function<'a> { | FunctionType::JsonExtractFirstArrayElem(_) ) } - pub fn returns_geometry(&self) -> bool { - matches!( - self.typ_, - FunctionType::GeomFromText(_) | FunctionType::GeomFromGeoJson(_) - ) - } } /// A database function type @@ -104,10 +88,6 @@ pub(crate) enum FunctionType<'a> { UuidToBin, UuidToBinSwapped, Uuid, - GeomAsText(GeomAsText<'a>), - GeomFromText(GeomFromText<'a>), - GeomAsGeoJson(GeomAsGeoJson<'a>), - GeomFromGeoJson(GeomFromGeoJson<'a>), } impl<'a> Aliasable<'a> for Function<'a> { @@ -153,6 +133,3 @@ function!( Coalesce, Concat ); - -function!(GeomAsText, GeomFromText); -function!(GeomAsGeoJson, GeomFromGeoJson); diff --git a/quaint/src/ast/function/geom_as_geojson.rs b/quaint/src/ast/function/geom_as_geojson.rs deleted file mode 100644 index db814a81b782..000000000000 --- a/quaint/src/ast/function/geom_as_geojson.rs +++ /dev/null @@ -1,31 +0,0 @@ -use super::Function; -use crate::ast::Expression; - -/// A represention of the `ST_AsGeoJSON` function in the database. -#[derive(Debug, Clone, PartialEq)] -pub struct GeomAsGeoJson<'a> { - pub(crate) expression: Box>, -} - -/// Read the geometry expression into a GeoJson object. -/// -/// ```rust -/// # use quaint::{ast::*, visitor::{Visitor, Sqlite}}; -/// # fn main() -> Result<(), quaint::error::Error> { -/// let query = Select::from_table("users").value(geom_as_geojson(Column::from("location"))); -/// let (sql, _) = Sqlite::build(query)?; -/// -/// assert_eq!("SELECT AsGeoJSON(`location`) FROM `users`", sql); -/// # Ok(()) -/// # } -/// ``` -pub fn geom_as_geojson<'a, E>(expression: E) -> Function<'a> -where - E: Into>, -{ - let fun = GeomAsGeoJson { - expression: Box::new(expression.into()), - }; - - fun.into() -} diff --git a/quaint/src/ast/function/geom_as_text.rs b/quaint/src/ast/function/geom_as_text.rs deleted file mode 100644 index 8c189e75f122..000000000000 --- a/quaint/src/ast/function/geom_as_text.rs +++ /dev/null @@ -1,31 +0,0 @@ -use super::Function; -use crate::ast::Expression; - -/// A represention of the `ST_AsText` function in the database. -#[derive(Debug, Clone, PartialEq)] -pub struct GeomAsText<'a> { - pub(crate) expression: Box>, -} - -/// Read the geometry expression into a EWKT string. -/// -/// ```rust -/// # use quaint::{ast::*, visitor::{Visitor, Sqlite}}; -/// # fn main() -> Result<(), quaint::error::Error> { -/// let query = Select::from_table("users").value(geom_as_text(Column::from("location"))); -/// let (sql, _) = Sqlite::build(query)?; -/// -/// assert_eq!("SELECT AsEWKT(`location`) FROM `users`", sql); -/// # Ok(()) -/// # } -/// ``` -pub fn geom_as_text<'a, E>(expression: E) -> Function<'a> -where - E: Into>, -{ - let fun = GeomAsText { - expression: Box::new(expression.into()), - }; - - fun.into() -} diff --git a/quaint/src/ast/function/geom_from_geojson.rs b/quaint/src/ast/function/geom_from_geojson.rs deleted file mode 100644 index 6ee667b5f9d6..000000000000 --- a/quaint/src/ast/function/geom_from_geojson.rs +++ /dev/null @@ -1,35 +0,0 @@ -use super::Function; -use crate::ast::Expression; - -/// A represention of the `ST_AsText` function in the database. -#[derive(Debug, Clone, PartialEq)] -pub struct GeomFromGeoJson<'a> { - pub(crate) expression: Box>, -} - -/// Write a GeoJson geometry value using built-in database conversion. -/// -/// ```rust -/// # use quaint::{ast::*, visitor::{Visitor, Sqlite}}; -/// # fn main() -> Result<(), quaint::error::Error> { -/// let query = Insert::single_into("users").value("location", geom_from_geojson("POINT(0 0)")); -/// let (sql, params) = Sqlite::build(query)?; -/// -/// assert_eq!("INSERT INTO `users` (`location`) VALUES (GeomFromGeoJSON(?))", sql); -/// -/// assert_eq!(vec![ -/// Value::from("POINT(0 0)"), -/// ], params); -/// # Ok(()) -/// # } -/// ``` -pub fn geom_from_geojson<'a, G>(expression: G) -> Function<'a> -where - G: Into>, -{ - let fun = GeomFromGeoJson { - expression: Box::new(expression.into()), - }; - - fun.into() -} diff --git a/quaint/src/ast/function/geom_from_text.rs b/quaint/src/ast/function/geom_from_text.rs deleted file mode 100644 index fcbfc59eec5b..000000000000 --- a/quaint/src/ast/function/geom_from_text.rs +++ /dev/null @@ -1,41 +0,0 @@ -use super::Function; -use crate::ast::Expression; - -/// A represention of the `ST_AsText` function in the database. -#[derive(Debug, Clone, PartialEq)] -pub struct GeomFromText<'a> { - pub(crate) wkt_expression: Box>, - pub(crate) srid_expression: Option>>, - pub(crate) geography: bool, -} - -/// Write a WKT geometry value using built-in database conversion. -/// -/// ```rust -/// # use quaint::{ast::*, visitor::{Visitor, Sqlite}}; -/// # fn main() -> Result<(), quaint::error::Error> { -/// let query = Insert::single_into("users").value("location", geom_from_text("POINT(0 0)", 4326, false)); -/// let (sql, params) = Sqlite::build(query)?; -/// -/// assert_eq!("INSERT INTO `users` (`location`) VALUES (ST_GeomFromText(?,?))", sql); -/// -/// assert_eq!(vec![ -/// Value::from("POINT(0 0)"), -/// Value::from(4326) -/// ], params); -/// # Ok(()) -/// # } -/// ``` -pub fn geom_from_text<'a, G, S>(wkt_expression: G, srid_expression: Option, geography: bool) -> Function<'a> -where - G: Into>, - S: Into>, -{ - let fun = GeomFromText { - wkt_expression: Box::new(wkt_expression.into()), - srid_expression: srid_expression.map(|s| Box::new(s.into())), - geography, - }; - - fun.into() -} diff --git a/quaint/src/geometry.rs b/quaint/src/geometry.rs new file mode 100644 index 000000000000..f1adac9a66ef --- /dev/null +++ b/quaint/src/geometry.rs @@ -0,0 +1,14 @@ +pub fn get_geometry_srid(geom: &geojson::Geometry) -> Option { + geom.foreign_members + .as_ref()? + .get("crs")? + .as_object()? + .get("properties")? + .as_object()? + .get("name")? + .as_str()? + .rsplit_once(":")? + .1 + .parse() + .ok() +} diff --git a/quaint/src/lib.rs b/quaint/src/lib.rs index 45c2a10a1698..75eb1aace370 100644 --- a/quaint/src/lib.rs +++ b/quaint/src/lib.rs @@ -130,3 +130,5 @@ pub mod visitor; pub use ast::{Value, ValueType}; pub type Result = std::result::Result; + +mod geometry; diff --git a/quaint/src/visitor.rs b/quaint/src/visitor.rs index 34e31856bdeb..3e97dcb773d8 100644 --- a/quaint/src/visitor.rs +++ b/quaint/src/visitor.rs @@ -137,18 +137,6 @@ pub trait Visitor<'a> { fn visit_json_build_object(&mut self, build_obj: JsonBuildObject<'a>) -> Result; - fn visit_geom_as_text(&mut self, geom: GeomAsText<'a>) -> Result; - - fn visit_geom_from_text(&mut self, geom: GeomFromText<'a>) -> Result; - - fn visit_geom_as_geojson(&mut self, _geom: GeomAsGeoJson<'a>) -> Result { - unimplemented!("GeomAsGeoJson not supported for the underlying database.") - } - - fn visit_geom_from_geojson(&mut self, _geom: GeomFromGeoJson<'a>) -> Result { - unimplemented!("GeomFromGeoJson not supported for the underlying database.") - } - fn visit_geometry_type_equals(&mut self, left: Expression<'a>, right: GeometryType<'a>, not: bool) -> Result; fn visit_geometry_empty(&mut self, left: Expression<'a>, not: bool) -> Result { @@ -225,13 +213,9 @@ pub trait Visitor<'a> { Ok(()) } - fn visit_parameterized_geometry(&mut self, geometry: geojson::Geometry) -> Result { - self.visit_function(geom_from_geojson(geometry.to_string())) - } + fn visit_parameterized_geometry(&mut self, geometry: geojson::Geometry) -> Result; - fn visit_parameterized_geography(&mut self, geometry: geojson::Geometry) -> Result { - self.visit_function(geom_from_geojson(geometry.to_string())) - } + fn visit_parameterized_geography(&mut self, geometry: geojson::Geometry) -> Result; /// A visit to a value we parameterize fn visit_parameterized(&mut self, value: Value<'a>) -> Result { @@ -680,12 +664,14 @@ pub trait Visitor<'a> { ExpressionKind::Default => self.write("DEFAULT")?, } - if let Some(alias) = value.alias { - self.write(" AS ")?; + self.visit_alias(value.alias) + } + fn visit_alias(&mut self, alias: Option>) -> Result { + if let Some(alias) = alias { + self.write(" AS ")?; self.delimited_identifiers(&[&*alias])?; }; - Ok(()) } @@ -728,42 +714,30 @@ pub trait Visitor<'a> { }; if include_alias { - if let Some(alias) = table.alias { - self.write(" AS ")?; - - self.delimited_identifiers(&[&*alias])?; - }; + self.visit_alias(table.alias)?; } Ok(()) } - fn visit_geometry_column(&mut self, mut column: Column<'a>) -> Result { - column.alias = None; - column.is_selected = false; - self.visit_function(geom_as_geojson(column)) - } + fn visit_geometry_column(&mut self, column: Column<'a>) -> Result; /// A database column identifier fn visit_column(&mut self, column: Column<'a>) -> Result { - let alias = column.alias.clone(); if column.is_geometry && column.is_selected { - self.visit_geometry_column(column)?; - } else { - match column.table { - Some(table) => { - self.visit_table(table, false)?; - self.write(".")?; - self.delimited_identifiers(&[&*column.name])?; - } - _ => self.delimited_identifiers(&[&*column.name])?, - }; + return self.visit_geometry_column(column); } - if let Some(alias) = alias { - self.write(" AS ")?; - self.delimited_identifiers(&[&*alias])?; - } + match column.table { + Some(table) => { + self.visit_table(table, false)?; + self.write(".")?; + self.delimited_identifiers(&[&*column.name])?; + } + _ => self.delimited_identifiers(&[&*column.name])?, + }; + + self.visit_alias(column.alias)?; Ok(()) } @@ -1217,18 +1191,6 @@ pub trait Visitor<'a> { FunctionType::JsonBuildObject(build_obj) => { self.visit_json_build_object(build_obj)?; } - FunctionType::GeomAsText(geom) => { - self.visit_geom_as_text(geom)?; - } - FunctionType::GeomFromText(geom) => { - self.visit_geom_from_text(geom)?; - } - FunctionType::GeomAsGeoJson(geom) => { - self.visit_geom_as_geojson(geom)?; - } - FunctionType::GeomFromGeoJson(geom) => { - self.visit_geom_from_geojson(geom)?; - } }; if let Some(alias) = fun.alias { diff --git a/quaint/src/visitor/mssql.rs b/quaint/src/visitor/mssql.rs index e70932d4b1e3..e08939afe94c 100644 --- a/quaint/src/visitor/mssql.rs +++ b/quaint/src/visitor/mssql.rs @@ -6,6 +6,7 @@ use crate::prelude::{JsonArrayAgg, JsonBuildObject, JsonExtract, JsonType, JsonU use crate::{ ast::*, error::{Error, ErrorKind}, + geometry::get_geometry_srid, prelude::{Aliasable, Average, Query}, visitor, Value, ValueType, }; @@ -22,23 +23,8 @@ pub struct Mssql<'a> { order_by_set: bool, } -fn get_geojson_srid(geom: &geojson::Geometry) -> Option { - geom.foreign_members - .as_ref()? - .get("crs")? - .as_object()? - .get("properties")? - .as_object()? - .get("name")? - .as_str()? - .rsplit_once(":")? - .1 - .parse() - .ok() -} - fn get_wkt_srid_from_geojson(geometry: &geojson::Geometry) -> crate::Result<(String, i32)> { - let srid = get_geojson_srid(geometry).unwrap_or(4326); + let srid = get_geometry_srid(geometry).unwrap_or(4326); let wkt = geozero::geojson::GeoJsonString(geometry.to_string()).to_wkt()?; Ok((wkt, srid)) } @@ -212,6 +198,20 @@ impl<'a> Mssql<'a> { self.surround_with(".STEquals(", ")", |s| s.visit_expression(right))?; self.write(if not { " = 0" } else { " = 1" }) } + + fn visit_geometry_from_wkt_srid(&mut self, wkt: G, srid: S, geography: bool) -> visitor::Result + where + G: Into>, + S: Into>, + { + self.write(if geography { "geography" } else { "geometry" })?; + self.surround_with("::STGeomFromText(", ")", |ref mut s| { + s.visit_expression(wkt.into())?; + s.write(",")?; + s.visit_expression(srid.into())?; + Ok(()) + }) + } } impl<'a> Visitor<'a> for Mssql<'a> { @@ -278,12 +278,12 @@ impl<'a> Visitor<'a> for Mssql<'a> { fn visit_parameterized_geometry(&mut self, geometry: geojson::Geometry) -> visitor::Result { let (wkt, srid) = get_wkt_srid_from_geojson(&geometry)?; - self.visit_function(geom_from_text(wkt, Some(srid), false)) + self.visit_geometry_from_wkt_srid(wkt, srid, false) } fn visit_parameterized_geography(&mut self, geometry: geojson::Geometry) -> visitor::Result { let (wkt, srid) = get_wkt_srid_from_geojson(&geometry)?; - self.visit_function(geom_from_text(wkt, Some(srid), true)) + self.visit_geometry_from_wkt_srid(wkt, srid, true) } /// A point to modify an incoming query to make it compatible with the @@ -456,11 +456,11 @@ impl<'a> Visitor<'a> for Mssql<'a> { ValueType::Xml(cow) => cow.map(|cow| self.write(format!("CONVERT(XML, N'{cow}', 3)"))), ValueType::Geometry(geojson) => geojson.map(|g| { let (wkt, srid) = get_wkt_srid_from_geojson(&g)?; - self.visit_function(geom_from_text(wkt.raw(), Some(srid.raw()), false)) + self.visit_geometry_from_wkt_srid(wkt.raw(), srid.raw(), false) }), ValueType::Geography(geojson) => geojson.map(|g| { let (wkt, srid) = get_wkt_srid_from_geojson(&g)?; - self.visit_function(geom_from_text(wkt.raw(), Some(srid.raw()), true)) + self.visit_geometry_from_wkt_srid(wkt.raw(), srid.raw(), true) }), }; @@ -852,41 +852,21 @@ impl<'a> Visitor<'a> for Mssql<'a> { fn visit_geometry_column(&mut self, column: Column<'a>) -> visitor::Result { // SQL Server does not support GeoJSON, so we return EWKT instead - self.visit_function(geom_as_text(column)) - } - - fn visit_geom_as_text(&mut self, geom: GeomAsText<'a>) -> visitor::Result { + let column = column.into_bare_with_table(); self.write("CASE WHEN ")?; - self.visit_expression(*geom.expression.clone())?; + self.visit_column(column.clone())?; self.write("IS NULL THEN NULL ELSE ")?; self.surround_with("CONCAT(", ")", |ref mut s| { s.write("'SRID=',")?; - s.surround_with("(", ").STSrid", |ref mut s| { - s.visit_expression(*geom.expression.clone()) - })?; + s.surround_with("(", ").STSrid", |ref mut s| s.visit_column(column.clone()))?; s.write(",';',")?; - s.surround_with("CAST(", " AS VARCHAR(MAX))", |ref mut s| { - s.visit_expression(*geom.expression) - })?; + s.surround_with("CAST(", " AS VARCHAR(MAX))", |ref mut s| s.visit_column(column.clone()))?; Ok(()) })?; self.write("END")?; + self.visit_alias(column.alias)?; Ok(()) } - - fn visit_geom_from_text(&mut self, geom: GeomFromText<'a>) -> visitor::Result { - self.write(if geom.geography { "geography" } else { "geometry" })?; - self.surround_with("::STGeomFromText(", ")", |ref mut s| { - s.visit_expression(*geom.wkt_expression)?; - s.write(",")?; - if geom.geography { - s.visit_expression(*geom.srid_expression.unwrap_or_else(|| Box::new(4326.into())))?; - } else { - s.visit_expression(*geom.srid_expression.unwrap_or_else(|| Box::new(0.into())))?; - } - Ok(()) - }) - } } #[cfg(test)] diff --git a/quaint/src/visitor/mysql.rs b/quaint/src/visitor/mysql.rs index a9b00183cf4d..0e2a3eadeab1 100644 --- a/quaint/src/visitor/mysql.rs +++ b/quaint/src/visitor/mysql.rs @@ -120,6 +120,15 @@ impl<'a> Mysql<'a> { _ => self.visit_expression(expr), } } + + fn visit_geometry_from_geojson(&mut self, geometry: E) -> visitor::Result + where + E: Into>, + { + self.surround_with("ST_GeomFromGeoJSON(", ")", |ref mut s| { + s.visit_expression(geometry.into()) + }) + } } impl<'a> Visitor<'a> for Mysql<'a> { @@ -195,10 +204,10 @@ impl<'a> Visitor<'a> for Mysql<'a> { ValueType::Xml(cow) => cow.as_ref().map(|cow| self.write(format!("'{cow}'"))), ValueType::Geometry(g) => g .as_ref() - .map(|g| self.visit_function(geom_from_geojson(g.to_string().raw()))), + .map(|g| self.visit_geometry_from_geojson(g.to_string().raw())), ValueType::Geography(g) => g .as_ref() - .map(|g| self.visit_function(geom_from_geojson(g.to_string().raw()))), + .map(|g| self.visit_geometry_from_geojson(g.to_string().raw())), }; match res { @@ -699,42 +708,24 @@ impl<'a> Visitor<'a> for Mysql<'a> { Ok(()) } - fn visit_geom_as_text(&mut self, geom: GeomAsText<'a>) -> visitor::Result { - self.surround_with("CONCAT(", ")", |ref mut s| { - s.write("'SRID=',")?; - s.surround_with("ST_SRID(", ")", |ref mut s| { - s.visit_expression(*geom.expression.clone()) - })?; - s.write(",';',")?; - s.surround_with("ST_AsText(", ")", |ref mut s| s.visit_expression(*geom.expression))?; - Ok(()) - }) - } - - fn visit_geom_from_text(&mut self, geom: GeomFromText<'a>) -> visitor::Result { - self.surround_with("ST_GeomFromText(", ")", |ref mut s| { - s.visit_expression(*geom.wkt_expression)?; - if let Some(srid_expression) = geom.srid_expression { - s.write(",")?; - s.visit_expression(*srid_expression)?; - } - Ok(()) - }) - } - - fn visit_geom_as_geojson(&mut self, geom: GeomAsGeoJson<'a>) -> visitor::Result { + fn visit_geometry_column(&mut self, column: Column<'a>) -> visitor::Result { self.surround_with("ST_AsGeoJSON(", ")", |s| { - s.visit_expression(*geom.expression)?; + s.visit_column(column.clone().into_bare_with_table())?; s.write(", 15, 2")?; Ok(()) - }) + })?; + self.visit_alias(column.alias) } - fn visit_geom_from_geojson(&mut self, geom: GeomFromGeoJson<'a>) -> visitor::Result { + fn visit_parameterized_geometry(&mut self, geometry: geojson::Geometry) -> visitor::Result { self.surround_with("ST_GeomFromGeoJSON(", ")", |ref mut s| { - s.visit_expression(*geom.expression) + s.visit_expression(geometry.to_string().into()) }) } + + fn visit_parameterized_geography(&mut self, geometry: geojson::Geometry) -> visitor::Result { + self.visit_parameterized_geometry(geometry) + } } fn get_target_table<'a>(query: &Query<'a>) -> Option> { diff --git a/quaint/src/visitor/postgres.rs b/quaint/src/visitor/postgres.rs index dd32af86b4c6..5ea55ea0221b 100644 --- a/quaint/src/visitor/postgres.rs +++ b/quaint/src/visitor/postgres.rs @@ -1,5 +1,6 @@ use crate::{ ast::*, + geometry::get_geometry_srid, visitor::{self, Visitor}, }; use itertools::Itertools; @@ -43,6 +44,39 @@ impl<'a> Postgres<'a> { } Ok(()) } + + fn visit_geometry_from_geojson(&mut self, geometry: G, srid: Option) -> visitor::Result + where + G: Into>, + S: Into>, + { + // We shouldn't have to do that but are forced to because CockroachDb doesn't parse the CRS information + // from the geojson string like PostGIS does. (https://github.com/cockroachdb/cockroach/issues/132046) + + if let Some(srid) = srid { + self.surround_with("ST_SetSRID(", ")", |s| { + s.visit_geometry(geometry.into())?; + s.write(",")?; + s.visit_expression(srid.into())?; + Ok(()) + }) + } else { + self.visit_geometry(geometry.into()) + } + } + + fn visit_geography_from_geojson(&mut self, geometry: G, srid: Option) -> visitor::Result + where + G: Into>, + S: Into>, + { + self.visit_geometry_from_geojson(geometry, srid)?; + self.write("::geography") + } + + fn visit_geometry(&mut self, geometry: Expression<'a>) -> visitor::Result { + self.surround_with("ST_GeomFromGeoJSON(", ")", |ref mut s| s.visit_expression(geometry)) + } } impl<'a> Visitor<'a> for Postgres<'a> { @@ -139,28 +173,27 @@ impl<'a> Visitor<'a> for Postgres<'a> { /// A database column identifier fn visit_column(&mut self, column: Column<'a>) -> visitor::Result { - let alias = column.alias.clone(); if column.is_geometry && column.is_selected { - self.visit_geometry_column(column)?; - } else { - match column.table { - Some(table) => { - self.visit_table(table, false)?; - self.write(".")?; - self.delimited_identifiers(&[&*column.name])?; - } - _ => self.delimited_identifiers(&[&*column.name])?, - }; - if column.is_enum && column.is_selected { - if column.is_list { - self.write("::text[]")?; - } else { - self.write("::text")?; - } + return self.visit_geometry_column(column); + } + + match column.table { + Some(table) => { + self.visit_table(table, false)?; + self.write(".")?; + self.delimited_identifiers(&[&*column.name])?; + } + _ => self.delimited_identifiers(&[&*column.name])?, + }; + if column.is_enum && column.is_selected { + if column.is_list { + self.write("::text[]")?; + } else { + self.write("::text")?; } } - if let Some(alias) = alias { + if let Some(alias) = column.alias { self.write(" AS ")?; self.delimited_identifiers(&[&*alias])?; } @@ -261,12 +294,14 @@ impl<'a> Visitor<'a> for Postgres<'a> { ValueType::DateTime(dt) => dt.map(|dt| self.write(format!("'{}'", dt.to_rfc3339(),))), ValueType::Date(date) => date.map(|date| self.write(format!("'{date}'"))), ValueType::Time(time) => time.map(|time| self.write(format!("'{time}'"))), - ValueType::Geometry(g) => g - .as_ref() - .map(|g| self.visit_function(geom_from_geojson(g.to_string().raw()))), - ValueType::Geography(g) => g - .as_ref() - .map(|g| self.visit_function(geom_from_geojson(g.to_string().raw()))), + ValueType::Geometry(geometry) => geometry.as_ref().map(|geometry| { + let srid = get_geometry_srid(geometry); + self.visit_geometry_from_geojson(geometry.to_string().raw(), srid.map(IntoRaw::raw)) + }), + ValueType::Geography(geometry) => geometry.as_ref().map(|geometry| { + let srid = get_geometry_srid(geometry); + self.visit_geography_from_geojson(geometry.to_string().raw(), srid.map(IntoRaw::raw)) + }), }; match res { @@ -788,33 +823,32 @@ impl<'a> Visitor<'a> for Postgres<'a> { Ok(()) } - fn visit_geom_as_text(&mut self, geom: GeomAsText<'a>) -> visitor::Result { - self.surround_with("ST_AsEWKT(", ")", |s| s.visit_expression(*geom.expression)) - } - - fn visit_geom_from_text(&mut self, geom: GeomFromText<'a>) -> visitor::Result { - self.surround_with("ST_GeomFromText(", ")", |ref mut s| { - s.visit_expression(*geom.wkt_expression)?; - if let Some(srid_expression) = geom.srid_expression { - s.write(",")?; - s.visit_expression(*srid_expression)?; - } + fn visit_geometry_column(&mut self, column: Column<'a>) -> visitor::Result { + self.surround_with("ST_AsGeoJSON(", ")", |s| { + s.visit_column(column.clone().into_bare_with_table())?; + s.write(", 15, 8")?; Ok(()) - }) + })?; + self.visit_alias(column.alias)?; + + Ok(()) } - fn visit_geom_as_geojson(&mut self, geom: GeomAsGeoJson<'a>) -> visitor::Result { - self.surround_with("ST_AsGeoJSON(", ")", |s| { - s.visit_expression(*geom.expression)?; - s.write(", 15")?; + fn visit_parameterized_geometry(&mut self, geometry: geojson::Geometry) -> visitor::Result { + let srid = get_geometry_srid(&geometry); + self.surround_with("ST_SetSRID(", ")", |s| { + s.visit_geometry_from_geojson(geometry.to_string(), srid)?; + s.write(",")?; + s.visit_expression(srid.into())?; Ok(()) }) } - fn visit_geom_from_geojson(&mut self, geom: GeomFromGeoJson<'a>) -> visitor::Result { - self.surround_with("ST_GeomFromGeoJSON(", ")", |ref mut s| { - s.visit_expression(*geom.expression) - }) + fn visit_parameterized_geography(&mut self, geometry: geojson::Geometry) -> visitor::Result { + self.visit_parameterized_geometry(geometry)?; + self.write("::geography")?; + + Ok(()) } } @@ -1235,10 +1269,20 @@ mod tests { #[test] fn test_raw_geometry() { - let geojson = r#"{"type":"Point","coordinates":[1.0,2.0]}"#; + let geojson = + r#"{"type":"Point","coordinates":[1.0,2.0],"crs":{"type":"name","properties":{"name":"EPSG:3857"}}}"#; let geom = geojson.parse::().unwrap(); let (sql, params) = Postgres::build(Select::default().value(Value::geometry(geom).raw())).unwrap(); - assert_eq!(format!("SELECT ST_GeomFromGeoJSON('{geojson}')"), sql); + assert_eq!(format!("SELECT ST_SetSRID(ST_GeomFromGeoJSON('{geojson}'),3857)"), sql); + assert!(params.is_empty()); + } + + #[test] + fn test_raw_geography() { + let geojson = r#"{"type":"Point","coordinates":[1.0,2.0]}"#; + let geom = geojson.parse::().unwrap(); + let (sql, params) = Postgres::build(Select::default().value(Value::geography(geom).raw())).unwrap(); + assert_eq!(format!("SELECT ST_GeomFromGeoJSON('{geojson}')::geography"), sql); assert!(params.is_empty()); } diff --git a/quaint/src/visitor/sqlite.rs b/quaint/src/visitor/sqlite.rs index b875cb28aa33..655e712c4d0e 100644 --- a/quaint/src/visitor/sqlite.rs +++ b/quaint/src/visitor/sqlite.rs @@ -33,6 +33,13 @@ impl<'a> Sqlite<'a> { } Ok(()) } + + fn visit_geometry_from_geojson(&mut self, geometry: G) -> visitor::Result + where + G: Into>, + { + self.surround_with("GeomFromGeoJSON(", ")", |ref mut s| s.visit_expression(geometry.into())) + } } impl<'a> Sqlite<'a> { @@ -139,10 +146,10 @@ impl<'a> Visitor<'a> for Sqlite<'a> { ValueType::Xml(cow) => cow.as_ref().map(|cow| self.write(format!("'{cow}'"))), ValueType::Geometry(g) => g .as_ref() - .map(|g| self.visit_function(geom_from_geojson(g.to_string().raw()))), + .map(|g| self.visit_geometry_from_geojson(g.to_string().raw())), ValueType::Geography(g) => g .as_ref() - .map(|g| self.visit_function(geom_from_geojson(g.to_string().raw()))), + .map(|g| self.visit_geometry_from_geojson(g.to_string().raw())), }; match res { @@ -491,33 +498,21 @@ impl<'a> Visitor<'a> for Sqlite<'a> { Ok(()) } - fn visit_geom_as_text(&mut self, geom: GeomAsText<'a>) -> visitor::Result { - self.surround_with("AsEWKT(", ")", |s| s.visit_expression(*geom.expression)) - } - - fn visit_geom_from_text(&mut self, geom: GeomFromText<'a>) -> visitor::Result { - self.surround_with("ST_GeomFromText(", ")", |ref mut s| { - s.visit_expression(*geom.wkt_expression)?; - if let Some(srid_expression) = geom.srid_expression { - s.write(",")?; - s.visit_expression(*srid_expression)?; - } - Ok(()) - }) - } - - fn visit_geom_as_geojson(&mut self, geom: GeomAsGeoJson<'a>) -> visitor::Result { + fn visit_geometry_column(&mut self, column: Column<'a>) -> visitor::Result { self.surround_with("AsGeoJSON(", ")", |s| { - s.visit_expression(*geom.expression)?; + s.visit_column(column.clone().into_bare_with_table())?; s.write(", 15, 2")?; Ok(()) - }) + })?; + self.visit_alias(column.alias) } - fn visit_geom_from_geojson(&mut self, geom: GeomFromGeoJson<'a>) -> visitor::Result { - self.surround_with("GeomFromGeoJSON(", ")", |ref mut s| { - s.visit_expression(*geom.expression) - }) + fn visit_parameterized_geometry(&mut self, geometry: geojson::Geometry) -> visitor::Result { + self.visit_geometry_from_geojson(geometry.to_string()) + } + + fn visit_parameterized_geography(&mut self, geometry: geojson::Geometry) -> visitor::Result { + self.visit_geometry_from_geojson(geometry.to_string()) } } diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs index c97424f46178..ab2de75446ff 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mysql.rs @@ -478,7 +478,9 @@ mod mysql { } }"#, MySql(Some(MySqlVersion::V8)) => r###"{"data":{"createOneModel":{"geometry":"{\"coordinates\":[1.0,2.0],\"type\":\"Point\"}","point":"{\"coordinates\":[1.0,2.0],\"type\":\"Point\"}","line":"{\"coordinates\":[[1.0,2.0],[3.0,4.0]],\"type\":\"LineString\"}","poly":"{\"coordinates\":[[[1.0,2.0],[3.0,4.0],[5.0,6.0],[1.0,2.0]]],\"type\":\"Polygon\"}","multipoint":"{\"coordinates\":[[1.0,2.0]],\"type\":\"MultiPoint\"}","multiline":"{\"coordinates\":[[[1.0,2.0],[3.0,4.0]]],\"type\":\"MultiLineString\"}","multipoly":"{\"coordinates\":[[[[1.0,2.0],[3.0,4.0],[5.0,6.0],[1.0,2.0]]]],\"type\":\"MultiPolygon\"}","collection":"{\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1.0,2.0]}],\"type\":\"GeometryCollection\"}"}}}"###, - _ => r###"{"data":{"createOneModel":{"geometry":"{\"coordinates\":[1,2],\"type\":\"Point\"}","point":"{\"coordinates\":[1,2],\"type\":\"Point\"}","line":"{\"coordinates\":[[1,2],[3,4]],\"type\":\"LineString\"}","poly":"{\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]],\"type\":\"Polygon\"}","multipoint":"{\"coordinates\":[[1,2]],\"type\":\"MultiPoint\"}","multiline":"{\"coordinates\":[[[1,2],[3,4]]],\"type\":\"MultiLineString\"}","multipoly":"{\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]],\"type\":\"MultiPolygon\"}","collection":"{\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}],\"type\":\"GeometryCollection\"}"}}}"### + MySql(Some(MySqlVersion::V5_7)) => r###"{"data":{"createOneModel":{"geometry":"{\"coordinates\":[1,2],\"type\":\"Point\"}","point":"{\"coordinates\":[1,2],\"type\":\"Point\"}","line":"{\"coordinates\":[[1,2],[3,4]],\"type\":\"LineString\"}","poly":"{\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]],\"type\":\"Polygon\"}","multipoint":"{\"coordinates\":[[1,2]],\"type\":\"MultiPoint\"}","multiline":"{\"coordinates\":[[[1,2],[3,4]]],\"type\":\"MultiLineString\"}","multipoly":"{\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]],\"type\":\"MultiPolygon\"}","collection":"{\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}],\"type\":\"GeometryCollection\"}"}}}"###, + MySql(Some(MySqlVersion::MariaDb)) => r###"{"data":{"createOneModel":{"geometry":"{\"type\":\"Point\",\"coordinates\":[1,2]}","point":"{\"type\":\"Point\",\"coordinates\":[1,2]}","line":"{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}","poly":"{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}","multipoint":"{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}","multiline":"{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}","multipoly":"{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}","collection":"{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}"}}}"###, + _ => r###"{"data":{"createOneModel":{"geometry":"{\"type\":\"Point\",\"coordinates\":[1,2]}","point":"{\"type\":\"Point\",\"coordinates\":[1,2]}","line":"{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}","poly":"{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}","multipoint":"{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}","multiline":"{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}","multipoly":"{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}","collection":"{\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}],\"type\":\"GeometryCollection\"}"}}}"### ); Ok(()) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/postgres.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/postgres.rs index fa21c57e8574..4d42508bfb68 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/postgres.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/postgres.rs @@ -542,8 +542,9 @@ mod postgres { db_schemas("public", "test") )] async fn native_geography_srid(runner: Runner) -> TestResult<()> { - insta::assert_snapshot!( - run_query!(&runner, r#"mutation { + match_connector_result!( + &runner, + r#"mutation { createOneModel( data: { geography: "{\"type\":\"Point\",\"coordinates\":[1,2],\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:9000\"}}}" @@ -565,8 +566,9 @@ mod postgres { geography_multipoly geography_collection } - }"#), - @r###"{"data":{"createOneModel":{"geography":"{\"type\":\"Point\",\"coordinates\":[1,2]}","geography_point":"{\"type\":\"Point\",\"coordinates\":[1,2]}","geography_line":"{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}","geography_poly":"{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}","geography_multipoint":"{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}","geography_multiline":"{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}","geography_multipoly":"{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}","geography_collection":"{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}"}}}"### + }"#, + CockroachDb(_) => r###"{"data":{"createOneModel":{"geography":"{\"type\":\"Point\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:9000\"}},\"coordinates\":[1,2]}","geography_point":"{\"type\":\"Point\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:9000\"}},\"coordinates\":[1,2]}","geography_line":"{\"type\":\"LineString\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:9000\"}},\"coordinates\":[[1,2],[3,4]]}","geography_poly":"{\"type\":\"Polygon\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:9000\"}},\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}","geography_multipoint":"{\"type\":\"MultiPoint\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:9000\"}},\"coordinates\":[[1,2]]}","geography_multiline":"{\"type\":\"MultiLineString\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:9000\"}},\"coordinates\":[[[1,2],[3,4]]]}","geography_multipoly":"{\"type\":\"MultiPolygon\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:9000\"}},\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}","geography_collection":"{\"type\":\"GeometryCollection\",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:9000\"}},\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}"}}}"###, + _ => r###"{"data":{"createOneModel":{"geography":"{\"type\":\"Point\",\"coordinates\":[1,2]}","geography_point":"{\"type\":\"Point\",\"coordinates\":[1,2]}","geography_line":"{\"type\":\"LineString\",\"coordinates\":[[1,2],[3,4]]}","geography_poly":"{\"type\":\"Polygon\",\"coordinates\":[[[1,2],[3,4],[5,6],[1,2]]]}","geography_multipoint":"{\"type\":\"MultiPoint\",\"coordinates\":[[1,2]]}","geography_multiline":"{\"type\":\"MultiLineString\",\"coordinates\":[[[1,2],[3,4]]]}","geography_multipoly":"{\"type\":\"MultiPolygon\",\"coordinates\":[[[[1,2],[3,4],[5,6],[1,2]]]]}","geography_collection":"{\"type\":\"GeometryCollection\",\"geometries\":[{\"type\":\"Point\",\"coordinates\":[1,2]}]}"}}}"### ); Ok(()) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs index cfbe7969a6d4..5999166a7b44 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs @@ -435,8 +435,8 @@ mod geometry_create { &runner, r#"mutation { createOneTestModel(data: { id: 1, geometry: "{\"type\":\"Point\",\"coordinates\":[1,2]}" }) { geometry }}"#, // MongoDB excludes undefined fields - MySql(Some(MySqlVersion::V8)) => vec![r#"{"data":{"createOneTestModel":{"geometry":"{\"coordinates\":[1.0,2.0],\"type\":\"Point\"}"}}}"#], MySql(Some(MySqlVersion::V5_7)) => vec![r#"{"data":{"createOneTestModel":{"geometry":"{\"coordinates\":[1,2],\"type\":\"Point\"}"}}}"#], + Vitess(_) | MySql(Some(MySqlVersion::V8) | None) => vec![r#"{"data":{"createOneTestModel":{"geometry":"{\"coordinates\":[1.0,2.0],\"type\":\"Point\"}"}}}"#], _ => vec![r#"{"data":{"createOneTestModel":{"geometry":"{\"type\":\"Point\",\"coordinates\":[1,2]}"}}}"#] ); diff --git a/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs b/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs index e5206fb6f3c9..b108de5450a1 100644 --- a/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs +++ b/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs @@ -66,7 +66,7 @@ impl ScalarFieldExt for ScalarField { // To facilitate geometry insertion, We manually set the GeoJSON CRS field // to the column constrained SRID if the latter is set to 4326 (the default) // or "unknown" (0 or -1). If there is no contraint at all, set it to 4326 - // anyway for conistency's sake, and also because SQL Server requires one + // anyway for consistency's sake, and also because SQL Server requires one // in order to create a geometry let geometry_crs = geometry.foreign_members.as_ref().and_then(|m| get_geometry_crs(m)); if geometry_crs.is_none() && matches!(column_srid, None | Some(-1 | 0 | 4326)) { From eb86df46ba828a0032d69a0bfb7b83ead8d8daa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Sun, 6 Oct 2024 23:21:40 +0200 Subject: [PATCH 070/103] Fix SQL Server geometry test --- .../tests/writes/data_types/native_types/sql_server.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sql_server.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sql_server.rs index 12593d38f482..b344cf155c9a 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sql_server.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/sql_server.rs @@ -390,7 +390,7 @@ mod sql_server { geog } }"#), - @r###"{"data":{"createOneModel":{"xml":"purr","uuid":"ab309dfd-d041-4110-b162-75d7b95fe989","geom":"{\"type\": \"Point\", \"coordinates\": [1,2]}","geog":"{\"type\": \"Point\", \"coordinates\": [1,2]}"}}}"### + @r###"{"data":{"createOneModel":{"xml":"purr","uuid":"ab309dfd-d041-4110-b162-75d7b95fe989","geom":"{\"type\":\"Point\",\"coordinates\":[1,2]}","geog":"{\"type\":\"Point\",\"coordinates\":[1,2]}"}}}"### ); Ok(()) From e15eaa56ce4d7ad05b30bca3361e160f74f38185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 7 Oct 2024 00:43:26 +0200 Subject: [PATCH 071/103] Run query engine tests on ubuntu latest --- .github/workflows/test-query-engine-template.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/test-query-engine-template.yml b/.github/workflows/test-query-engine-template.yml index fe9b42e6fd5c..87a5ff543923 100644 --- a/.github/workflows/test-query-engine-template.yml +++ b/.github/workflows/test-query-engine-template.yml @@ -49,9 +49,7 @@ jobs: PRISMA_ENGINE_PROTOCOL: ${{ matrix.engine_protocol }} PRISMA_RELATION_LOAD_STRATEGY: ${{ matrix.relation_load_strategy }} - runs-on: "ubuntu-20.04" - # TODO: Replace with the following once `prisma@5.20.0` is released. - # runs-on: "ubuntu-${{ inputs.ubuntu }}" + runs-on: "ubuntu-${{ inputs.ubuntu }}" steps: - uses: actions/checkout@v4 - uses: actions-rust-lang/setup-rust-toolchain@v1 From 963f1a9e32411d97feac74c66765631b8e207843 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 7 Oct 2024 03:40:32 +0200 Subject: [PATCH 072/103] Validate GeoJSON in mongodb connector --- Cargo.lock | 1 + .../connectors/mongodb-query-connector/Cargo.toml | 1 + .../connectors/mongodb-query-connector/src/error.rs | 4 ++++ .../connectors/mongodb-query-connector/src/value.rs | 8 +++++--- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1ccd9006006d..f17ebf819649 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2740,6 +2740,7 @@ dependencies = [ "cuid", "derive_more", "futures", + "geojson", "indexmap 2.2.2", "itertools 0.12.0", "mongodb", diff --git a/query-engine/connectors/mongodb-query-connector/Cargo.toml b/query-engine/connectors/mongodb-query-connector/Cargo.toml index e66ca4204021..9520463d882f 100644 --- a/query-engine/connectors/mongodb-query-connector/Cargo.toml +++ b/query-engine/connectors/mongodb-query-connector/Cargo.toml @@ -23,6 +23,7 @@ indexmap.workspace = true query-engine-metrics = { path = "../../metrics" } cuid = { git = "https://github.com/prisma/cuid-rust", branch = "wasm32-support" } derive_more = "0.99.17" +geojson = { version = "0.24.1", default-features = false } [dependencies.query-structure] path = "../../query-structure" diff --git a/query-engine/connectors/mongodb-query-connector/src/error.rs b/query-engine/connectors/mongodb-query-connector/src/error.rs index 8fcfaaaf041b..1cbf81aa413f 100644 --- a/query-engine/connectors/mongodb-query-connector/src/error.rs +++ b/query-engine/connectors/mongodb-query-connector/src/error.rs @@ -47,6 +47,9 @@ pub enum MongoError { #[error("{0}")] JsonError(#[from] serde_json::Error), + #[error("{0}")] + GeoJsonError(#[from] geojson::Error), + #[error("{0}")] BsonDeserializationError(#[from] bson::de::Error), @@ -94,6 +97,7 @@ impl MongoError { MongoError::UnhandledConversionError(err) => ConnectorError::from_kind(ErrorKind::ConversionError(err)), MongoError::UuidError(err) => ConnectorError::from_kind(ErrorKind::ConversionError(err.into())), MongoError::JsonError(err) => ConnectorError::from_kind(ErrorKind::ConversionError(err.into())), + MongoError::GeoJsonError(err) => ConnectorError::from_kind(ErrorKind::ConversionError(err.into())), MongoError::BsonDeserializationError(err) => { ConnectorError::from_kind(ErrorKind::ConversionError(err.into())) } diff --git a/query-engine/connectors/mongodb-query-connector/src/value.rs b/query-engine/connectors/mongodb-query-connector/src/value.rs index cc84d8628bac..eda8122e611d 100644 --- a/query-engine/connectors/mongodb-query-connector/src/value.rs +++ b/query-engine/connectors/mongodb-query-connector/src/value.rs @@ -12,7 +12,7 @@ use query_structure::{ CompositeFieldRef, Field, PrismaValue, RelationFieldRef, ScalarFieldRef, SelectedField, TypeIdentifier, }; use serde_json::Value; -use std::{convert::TryFrom, fmt::Display}; +use std::{convert::TryFrom, fmt::Display, str::FromStr}; /// Transforms a `PrismaValue` of a specific selected field into the BSON mapping as prescribed by /// the native types or as defined by the default `TypeIdentifier` to BSON mapping. @@ -200,7 +200,8 @@ impl IntoBson for (&MongoDbType, PrismaValue) { // Geometry (MongoDbType::Json, PrismaValue::GeoJson(json)) => { - let val: Value = serde_json::from_str(&json)?; + let geometry = geojson::Geometry::from_str(&json)?; + let val: Value = geojson::GeoJson::Geometry(geometry).into(); Bson::try_from(val).map_err(|_| MongoError::ConversionError { from: "Stringified GeoJSON".to_owned(), @@ -278,7 +279,8 @@ impl IntoBson for (&TypeIdentifier, PrismaValue) { // Geometry (TypeIdentifier::Geometry, PrismaValue::GeoJson(json)) => { - let val: Value = serde_json::from_str(&json)?; + let geometry = geojson::Geometry::from_str(&json)?; + let val: Value = geojson::GeoJson::Geometry(geometry).into(); Bson::try_from(val).map_err(|_| MongoError::ConversionError { from: "Stringified GeoJSON".to_owned(), to: "Mongo BSON (extJSON)".to_owned(), From c9479ddee6b42eaa7b72b497376fba99ddc5f32e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 7 Oct 2024 03:03:43 +0200 Subject: [PATCH 073/103] Remove GEoOJSON from query engine custom_types --- query-engine/core/src/constants.rs | 2 -- query-engine/core/src/response_ir/internal.rs | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/query-engine/core/src/constants.rs b/query-engine/core/src/constants.rs index 6f61e802ea84..f6a9eb403646 100644 --- a/query-engine/core/src/constants.rs +++ b/query-engine/core/src/constants.rs @@ -9,8 +9,6 @@ pub mod custom_types { pub const DECIMAL: &str = "Decimal"; pub const BYTES: &str = "Bytes"; pub const JSON: &str = "Json"; - pub const EWKT_GEOMETRY: &str = "Geometry"; - pub const GEOJSON: &str = "GeoJson"; pub const ENUM: &str = "Enum"; pub const FIELD_REF: &str = "FieldRef"; pub const RAW: &str = "Raw"; diff --git a/query-engine/core/src/response_ir/internal.rs b/query-engine/core/src/response_ir/internal.rs index 4910ac4636a1..5168f9deb782 100644 --- a/query-engine/core/src/response_ir/internal.rs +++ b/query-engine/core/src/response_ir/internal.rs @@ -855,7 +855,7 @@ fn convert_prisma_value_json_protocol( custom_types::make_object(custom_types::BYTES, PrismaValue::Bytes(x)) } (ScalarType::Geometry, PrismaValue::GeoJson(x)) => { - custom_types::make_object(custom_types::GEOJSON, PrismaValue::GeoJson(x)) + custom_types::make_object(custom_types::JSON, PrismaValue::GeoJson(x)) } // Identity matchers From 8b15e0688d38275490c7a1097e0d898b3d6e0001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 7 Oct 2024 03:31:40 +0200 Subject: [PATCH 074/103] Remove Geometry connector capabilities to allow stable build --- libs/user-facing-errors/src/lib.rs | 2 +- .../builtin_connectors/capabilities_support.rs | 2 +- .../cockroach_datamodel_connector.rs | 2 -- psl/psl-core/src/builtin_connectors/mongodb.rs | 1 - .../mssql_datamodel_connector.rs | 2 -- .../mysql_datamodel_connector.rs | 2 -- .../postgres_datamodel_connector.rs | 2 -- .../sqlite_datamodel_connector.rs | 2 -- psl/psl-core/src/datamodel_connector.rs | 4 ---- .../src/datamodel_connector/capabilities.rs | 4 +--- .../src/datamodel_connector/empty_connector.rs | 1 - psl/psl-core/src/lib.rs | 1 - .../validation_pipeline/validations/fields.rs | 16 ---------------- .../tests/queries/filters/geometry_filter.rs | 5 ++--- .../tests/writes/top_level_mutations/create.rs | 2 +- .../query-engine-wasm/rust-toolchain.toml | 2 +- rust-toolchain.toml | 2 +- 17 files changed, 8 insertions(+), 44 deletions(-) diff --git a/libs/user-facing-errors/src/lib.rs b/libs/user-facing-errors/src/lib.rs index 33f263418a27..7d7856831637 100644 --- a/libs/user-facing-errors/src/lib.rs +++ b/libs/user-facing-errors/src/lib.rs @@ -121,7 +121,7 @@ impl Error { /// Construct a new UnknownError from a `PanicInfo` in a panic hook. `UnknownError`s created /// with this constructor will have a proper, useful backtrace. - pub fn new_in_panic_hook(panic_info: &std::panic::PanicHookInfo<'_>) -> Self { + pub fn new_in_panic_hook(panic_info: &std::panic::PanicInfo<'_>) -> Self { let message = panic_info .payload() .downcast_ref::<&str>() diff --git a/psl/psl-core/src/builtin_connectors/capabilities_support.rs b/psl/psl-core/src/builtin_connectors/capabilities_support.rs index 5b666a8c7b8d..aef2d22cd076 100644 --- a/psl/psl-core/src/builtin_connectors/capabilities_support.rs +++ b/psl/psl-core/src/builtin_connectors/capabilities_support.rs @@ -83,7 +83,7 @@ macro_rules! reachable_only_with_capability { #[inline(always)] #[allow(dead_code)] // not used if more than one connector is built const fn check_comptime_capability(capabilities: ConnectorCapabilities, cap: ConnectorCapability) -> bool { - (capabilities.bits_c() & (cap as u128)) > 0 + (capabilities.bits_c() & (cap as u64)) > 0 } #[inline(always)] 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 4cec7868d4b1..088e51cc7e27 100644 --- a/psl/psl-core/src/builtin_connectors/cockroach_datamodel_connector.rs +++ b/psl/psl-core/src/builtin_connectors/cockroach_datamodel_connector.rs @@ -46,8 +46,6 @@ const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(Connector Json | JsonFiltering | JsonFilteringArrayPath | - Geometry | - GeometryFiltering | NamedPrimaryKeys | NamedForeignKeys | SqlQueryRaw | diff --git a/psl/psl-core/src/builtin_connectors/mongodb.rs b/psl/psl-core/src/builtin_connectors/mongodb.rs index bec283cff092..bc18956201ad 100644 --- a/psl/psl-core/src/builtin_connectors/mongodb.rs +++ b/psl/psl-core/src/builtin_connectors/mongodb.rs @@ -17,7 +17,6 @@ use std::result::Result as StdResult; const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(ConnectorCapability::{ Json | - Geometry | Enums | EnumArrayPush | RelationFieldsInArbitraryOrder | diff --git a/psl/psl-core/src/builtin_connectors/mssql_datamodel_connector.rs b/psl/psl-core/src/builtin_connectors/mssql_datamodel_connector.rs index b063ffbbf4f3..edf6a0711873 100644 --- a/psl/psl-core/src/builtin_connectors/mssql_datamodel_connector.rs +++ b/psl/psl-core/src/builtin_connectors/mssql_datamodel_connector.rs @@ -26,8 +26,6 @@ const CONSTRAINT_SCOPES: &[ConstraintScope] = &[ ]; const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(ConnectorCapability::{ - Geometry | - GeometryFiltering | AnyId | AutoIncrement | AutoIncrementAllowedOnNonId | diff --git a/psl/psl-core/src/builtin_connectors/mysql_datamodel_connector.rs b/psl/psl-core/src/builtin_connectors/mysql_datamodel_connector.rs index ca0319052444..66987ca9316f 100644 --- a/psl/psl-core/src/builtin_connectors/mysql_datamodel_connector.rs +++ b/psl/psl-core/src/builtin_connectors/mysql_datamodel_connector.rs @@ -37,8 +37,6 @@ pub const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(Conne Enums | EnumArrayPush | Json | - Geometry | - GeometryFiltering | AutoIncrementAllowedOnNonId | RelationFieldsInArbitraryOrder | CreateMany | diff --git a/psl/psl-core/src/builtin_connectors/postgres_datamodel_connector.rs b/psl/psl-core/src/builtin_connectors/postgres_datamodel_connector.rs index 3f7066c08139..d8ced5ca0159 100644 --- a/psl/psl-core/src/builtin_connectors/postgres_datamodel_connector.rs +++ b/psl/psl-core/src/builtin_connectors/postgres_datamodel_connector.rs @@ -50,8 +50,6 @@ pub const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(Conne JsonFilteringArrayPath | JsonFilteringAlphanumeric | JsonFilteringAlphanumericFieldRef | - Geometry | - GeometryFiltering | MultiSchema | NamedForeignKeys | NamedPrimaryKeys | diff --git a/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs b/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs index a9034e178d74..6b90abb98463 100644 --- a/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs +++ b/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs @@ -18,8 +18,6 @@ pub const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(Conne AnyId | AutoIncrement | CompoundIds | - Geometry | - GeometryFiltering | SqlQueryRaw | RelationFieldsInArbitraryOrder | UpdateableId | diff --git a/psl/psl-core/src/datamodel_connector.rs b/psl/psl-core/src/datamodel_connector.rs index d269f6c958f7..f88f560920e0 100644 --- a/psl/psl-core/src/datamodel_connector.rs +++ b/psl/psl-core/src/datamodel_connector.rs @@ -223,10 +223,6 @@ pub trait Connector: Send + Sync { } } - fn supports_geometry_type(&self) -> bool { - self.capabilities().contains(ConnectorCapability::Geometry) - } - fn supported_index_types(&self) -> BitFlags { IndexAlgorithm::BTree.into() } diff --git a/psl/psl-core/src/datamodel_connector/capabilities.rs b/psl/psl-core/src/datamodel_connector/capabilities.rs index 0f441fb99657..cf3f36eeea13 100644 --- a/psl/psl-core/src/datamodel_connector/capabilities.rs +++ b/psl/psl-core/src/datamodel_connector/capabilities.rs @@ -6,7 +6,7 @@ macro_rules! capabilities { ($( $variant:ident $(,)? ),*) => { #[derive(Debug, Clone, Copy, PartialEq)] #[enumflags2::bitflags] - #[repr(u128)] + #[repr(u64)] pub enum ConnectorCapability { $( $variant, @@ -55,8 +55,6 @@ capabilities!( TwoWayEmbeddedManyToManyRelation, ImplicitManyToManyRelation, MultiSchema, - Geometry, - GeometryFiltering, //Start of ME/IE only capabilities AutoIncrementAllowedOnNonId, AutoIncrementMultipleAllowed, diff --git a/psl/psl-core/src/datamodel_connector/empty_connector.rs b/psl/psl-core/src/datamodel_connector/empty_connector.rs index efd0517485a4..3aa97dfeaa13 100644 --- a/psl/psl-core/src/datamodel_connector/empty_connector.rs +++ b/psl/psl-core/src/datamodel_connector/empty_connector.rs @@ -25,7 +25,6 @@ impl Connector for EmptyDatamodelConnector { CompoundIds | Enums | Json | - Geometry | ImplicitManyToManyRelation }) } diff --git a/psl/psl-core/src/lib.rs b/psl/psl-core/src/lib.rs index dac097aa17ea..34a77c371640 100644 --- a/psl/psl-core/src/lib.rs +++ b/psl/psl-core/src/lib.rs @@ -2,7 +2,6 @@ #![deny(rust_2018_idioms, unsafe_code)] #![allow(clippy::derive_partial_eq_without_eq)] #![allow(incomplete_features)] -#![feature(repr128)] pub mod builtin_connectors; pub mod datamodel_connector; diff --git a/psl/psl-core/src/validate/validation_pipeline/validations/fields.rs b/psl/psl-core/src/validate/validation_pipeline/validations/fields.rs index 2ec5b6493e10..674d8e50d3bc 100644 --- a/psl/psl-core/src/validate/validation_pipeline/validations/fields.rs +++ b/psl/psl-core/src/validate/validation_pipeline/validations/fields.rs @@ -298,22 +298,6 @@ pub(super) fn validate_scalar_field_connector_specific(field: ScalarFieldWalker< } } - ScalarFieldType::BuiltInScalar(ScalarType::Geometry) => { - if !ctx.connector.supports_geometry_type() { - ctx.push_error(DatamodelError::new_field_validation_error( - &format!( - "Field `{}` in {container} `{}` can't be of type Geometry. The current connector does not support the Geometry type.", - field.name(), - field.model().name(), - ), - container, - field.model().name(), - field.name(), - field.ast_field().span(), - )); - } - } - _ => (), } diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs index aab9b008eebd..19cbdfbd85cd 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/filters/geometry_filter.rs @@ -1,6 +1,6 @@ use query_engine_tests::*; -#[test_suite(capabilities(Geometry))] +#[test_suite] mod geometry_filter_spec { use query_engine_tests::run_query; @@ -119,8 +119,7 @@ mod geometry_filter_spec { #[connector_test( schema(schema), - exclude(Postgres, Sqlite(3, "cfd1", "libsql.js", "libsql.js.wasm"), MySQL(5.6)), - capabilities(GeometryFiltering) + exclude(Postgres, Sqlite(3, "cfd1", "libsql.js", "libsql.js.wasm"), MySQL(5.6), MongoDb) )] async fn geometric_comparison_filters(runner: Runner) -> TestResult<()> { geometric_comparison_filters_test(runner).await diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs index 5999166a7b44..df06263a7087 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs @@ -425,7 +425,7 @@ mod mapped_create { } } -#[test_suite(capabilities(Geometry))] +#[test_suite] mod geometry_create { use query_engine_tests::run_query; diff --git a/query-engine/query-engine-wasm/rust-toolchain.toml b/query-engine/query-engine-wasm/rust-toolchain.toml index fab6164d265c..5048fd2e74a6 100644 --- a/query-engine/query-engine-wasm/rust-toolchain.toml +++ b/query-engine/query-engine-wasm/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "nightly-2024-09-29" +channel = "nightly-2024-05-25" components = ["clippy", "rustfmt", "rust-src"] targets = [ "wasm32-unknown-unknown", diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 9fcff05a670c..e48263a13878 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,5 +1,5 @@ [toolchain] -channel = "nightly" +channel = "1.80.1" components = ["clippy", "rustfmt", "rust-src"] targets = [ # WASM target for serverless and edge environments. From a5979013a073d150a4c2261213373e4d0d597c6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 7 Oct 2024 04:23:07 +0200 Subject: [PATCH 075/103] Fix mongodb tests --- .../tests/writes/data_types/native_types/mongodb.rs | 2 +- .../tests/writes/top_level_mutations/create.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mongodb.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mongodb.rs index 80f28e9e855d..309ea73924e0 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mongodb.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/mongodb.rs @@ -54,7 +54,7 @@ mod mongodb { geom } }"#), - @r###"{"data":{"createOneTestModel":{"int":2147483647,"long":32767,"bInt":"9223372036854775807","float":3.1234,"oid":"61e1425609c85b5e01817cc5","str":"test","bool":true,"bin":"dGVzdA==","bin_oid":"YeUuxAwj5igGOSD0","geom":"{\"type\":\"Point\",\"coordinates\":[0,0]}"}}}"### + @r###"{"data":{"createOneTestModel":{"int":2147483647,"long":32767,"bInt":"9223372036854775807","float":3.1234,"oid":"61e1425609c85b5e01817cc5","str":"test","bool":true,"bin":"dGVzdA==","bin_oid":"YeUuxAwj5igGOSD0","geom":"{\"type\":\"Point\",\"coordinates\":[0.0,0.0]}"}}}"### ); Ok(()) diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs index df06263a7087..d5c93c2d24a4 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/top_level_mutations/create.rs @@ -435,8 +435,9 @@ mod geometry_create { &runner, r#"mutation { createOneTestModel(data: { id: 1, geometry: "{\"type\":\"Point\",\"coordinates\":[1,2]}" }) { geometry }}"#, // MongoDB excludes undefined fields + MySql(Some(MySqlVersion::V8) | None) | Vitess(_) => vec![r#"{"data":{"createOneTestModel":{"geometry":"{\"coordinates\":[1.0,2.0],\"type\":\"Point\"}"}}}"#], MySql(Some(MySqlVersion::V5_7)) => vec![r#"{"data":{"createOneTestModel":{"geometry":"{\"coordinates\":[1,2],\"type\":\"Point\"}"}}}"#], - Vitess(_) | MySql(Some(MySqlVersion::V8) | None) => vec![r#"{"data":{"createOneTestModel":{"geometry":"{\"coordinates\":[1.0,2.0],\"type\":\"Point\"}"}}}"#], + MongoDb(_) => vec![r#"{"data":{"createOneTestModel":{"geometry":"{\"type\":\"Point\",\"coordinates\":[1.0,2.0]}"}}}"#], _ => vec![r#"{"data":{"createOneTestModel":{"geometry":"{\"type\":\"Point\",\"coordinates\":[1,2]}"}}}"#] ); From 302537f9b3aa71d925f49263ff41f90fd987c373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 7 Oct 2024 05:07:37 +0200 Subject: [PATCH 076/103] Update geozero feature flags --- Cargo.lock | 7 ------- quaint/Cargo.toml | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f17ebf819649..e0b5da724247 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1720,7 +1720,6 @@ checksum = "4b1b9a1eeae9ad09e12ec50243956105184b26440f81f978cd3aae009b214d4d" dependencies = [ "geojson", "log", - "scroll", "serde_json", "thiserror", "wkt", @@ -4904,12 +4903,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "scroll" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" - [[package]] name = "sct" version = "0.6.1" diff --git a/quaint/Cargo.toml b/quaint/Cargo.toml index 6b06d5bee221..a47147f35404 100644 --- a/quaint/Cargo.toml +++ b/quaint/Cargo.toml @@ -85,7 +85,7 @@ uuid.workspace = true crosstarget-utils = { path = "../libs/crosstarget-utils" } concat-idents = "1.1.5" once_cell = "1.3" -geozero = { version = "0.11.0", default-features = false, features = ["with-wkb", "with-geojson"] } +geozero = { version = "0.11.0", default-features = false, features = ["with-wkt", "with-geojson"] } geojson = { version = "0.24.1", default-features = false } [dev-dependencies] From b3e6d225cffbbc5589c858864f3fa7205491a0c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 7 Oct 2024 05:23:08 +0200 Subject: [PATCH 077/103] Move geojson and geozero dependencies to workspace --- Cargo.lock | 26 +++++-------------- Cargo.toml | 3 +++ quaint/Cargo.toml | 5 ++-- .../mongodb-query-connector/Cargo.toml | 2 +- .../connectors/sql-query-connector/Cargo.toml | 5 ++-- query-engine/core/Cargo.toml | 2 +- 6 files changed, 15 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e0b5da724247..0595d1e4d2f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1700,9 +1700,9 @@ dependencies = [ [[package]] name = "geozero" -version = "0.10.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "937818b9c084b253f929b5f5dbe050e744331d94ceb0a908b08873bcb2da3066" +checksum = "e5f28f34864745eb2f123c990c6ffd92c1584bd39439b3f27ff2a0f4ea5b309b" dependencies = [ "geo-types", "geojson", @@ -1712,19 +1712,6 @@ dependencies = [ "wkt", ] -[[package]] -name = "geozero" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b1b9a1eeae9ad09e12ec50243956105184b26440f81f978cd3aae009b214d4d" -dependencies = [ - "geojson", - "log", - "serde_json", - "thiserror", - "wkt", -] - [[package]] name = "getrandom" version = "0.1.16" @@ -3851,7 +3838,7 @@ dependencies = [ "expect-test", "futures", "geojson", - "geozero 0.11.0", + "geozero", "getrandom 0.2.11", "hex", "indoc 0.3.6", @@ -5333,7 +5320,7 @@ dependencies = [ "expect-test", "futures", "geojson", - "geozero 0.10.0", + "geozero", "itertools 0.12.0", "once_cell", "opentelemetry", @@ -5343,7 +5330,6 @@ dependencies = [ "query-connector", "query-structure", "rand 0.8.5", - "regex", "serde", "serde_json", "thiserror", @@ -6853,9 +6839,9 @@ dependencies = [ [[package]] name = "wkt" -version = "0.10.3" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c2252781f8927974e8ba6a67c965a759a2b88ea2b1825f6862426bbb1c8f41" +checksum = "296937617013271141d1145d9c05861f5ed3b1bc4297e81c692aa3cff9270a9c" dependencies = [ "geo-types", "log", diff --git a/Cargo.toml b/Cargo.toml index f2000ba619d3..4c4e1fc55c6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,6 +79,9 @@ url = { version = "2.5.0" } bson = { version = "2.11.0", features = ["chrono-0_4", "uuid-1"] } mongodb = { git = "https://github.com/prisma/mongo-rust-driver.git", branch = "RUST-1994/happy-eyeballs" } +geojson = { version = "0.24.1", default-features = false } +geozero = "0.14.0" + [workspace.dependencies.quaint] path = "quaint" diff --git a/quaint/Cargo.toml b/quaint/Cargo.toml index a47147f35404..b3f033b2e56c 100644 --- a/quaint/Cargo.toml +++ b/quaint/Cargo.toml @@ -84,9 +84,8 @@ sqlformat = { version = "0.2.3", optional = true } uuid.workspace = true crosstarget-utils = { path = "../libs/crosstarget-utils" } concat-idents = "1.1.5" -once_cell = "1.3" -geozero = { version = "0.11.0", default-features = false, features = ["with-wkt", "with-geojson"] } -geojson = { version = "0.24.1", default-features = false } +geozero.workspace = true +geojson.workspace = true [dev-dependencies] once_cell = "1.3" diff --git a/query-engine/connectors/mongodb-query-connector/Cargo.toml b/query-engine/connectors/mongodb-query-connector/Cargo.toml index 9520463d882f..0ae47208e51c 100644 --- a/query-engine/connectors/mongodb-query-connector/Cargo.toml +++ b/query-engine/connectors/mongodb-query-connector/Cargo.toml @@ -23,7 +23,7 @@ indexmap.workspace = true query-engine-metrics = { path = "../../metrics" } cuid = { git = "https://github.com/prisma/cuid-rust", branch = "wasm32-support" } derive_more = "0.99.17" -geojson = { version = "0.24.1", default-features = false } +geojson.workspace = true [dependencies.query-structure] path = "../../query-structure" diff --git a/query-engine/connectors/sql-query-connector/Cargo.toml b/query-engine/connectors/sql-query-connector/Cargo.toml index 5d2e90c1276e..4b7d8659d21b 100644 --- a/query-engine/connectors/sql-query-connector/Cargo.toml +++ b/query-engine/connectors/sql-query-connector/Cargo.toml @@ -51,10 +51,9 @@ uuid.workspace = true opentelemetry = { version = "0.17", features = ["tokio"] } tracing-opentelemetry = "0.17.3" cuid = { git = "https://github.com/prisma/cuid-rust", branch = "wasm32-support" } -regex = "1.9.3" -geozero = "0.10.0" quaint.workspace = true -geojson = { version = "0.24.1", default-features = false } +geojson.workspace = true +geozero.workspace = true [dev-dependencies] expect-test = "1" diff --git a/query-engine/core/Cargo.toml b/query-engine/core/Cargo.toml index 066d2fe2003e..e7972e385fab 100644 --- a/query-engine/core/Cargo.toml +++ b/query-engine/core/Cargo.toml @@ -40,4 +40,4 @@ schema = { path = "../schema" } crosstarget-utils = { path = "../../libs/crosstarget-utils" } lru = "0.7.7" enumflags2.workspace = true -geojson = { version = "0.24.1", default-features = false } +geojson.workspace = true From 87fc365d4b6f91826c57713eb0393221f89210de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 7 Oct 2024 06:07:28 +0200 Subject: [PATCH 078/103] Err instead of panic in sqlite schema connector creation --- .../connectors/sql-schema-connector/src/flavour/sqlite.rs | 2 +- .../sql-schema-connector/src/flavour/sqlite/connection.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite.rs b/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite.rs index e3ec9775165f..4860e34bc126 100644 --- a/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite.rs +++ b/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite.rs @@ -367,7 +367,7 @@ impl SqlFlavour for SqliteFlavour { ) -> BoxFuture<'a, ConnectorResult> { Box::pin(async move { tracing::debug!("Applying migrations to temporary in-memory SQLite database."); - let mut shadow_db_conn = Connection::new_in_memory(); + let mut shadow_db_conn = Connection::new_in_memory()?; for migration in migrations { let script = migration.read_migration_script()?; diff --git a/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite/connection.rs b/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite/connection.rs index b0532e505a84..18b8bb08765d 100644 --- a/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite/connection.rs +++ b/schema-engine/connectors/sql-schema-connector/src/flavour/sqlite/connection.rs @@ -15,14 +15,14 @@ pub(super) struct Connection(Mutex); impl Connection { pub(super) fn new(params: &super::Params) -> ConnectorResult { let conn = rusqlite::Connection::open(¶ms.file_path).map_err(convert_error)?; - load_spatialite(&conn).unwrap(); + load_spatialite(&conn).map_err(|e| ConnectorError::from_msg(e.to_string()))?; Ok(Connection(Mutex::new(conn))) } - pub(super) fn new_in_memory() -> Self { + pub(super) fn new_in_memory() -> ConnectorResult { let conn = rusqlite::Connection::open_in_memory().unwrap(); - load_spatialite(&conn).unwrap(); - Connection(Mutex::new(conn)) + load_spatialite(&conn).map_err(|e| ConnectorError::from_msg(e.to_string()))?; + Ok(Connection(Mutex::new(conn))) } pub(super) async fn describe_schema(&mut self) -> ConnectorResult { From 8ed9ffde1be7c4e0257d677c674594b077d5753b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 7 Oct 2024 06:07:56 +0200 Subject: [PATCH 079/103] Replace deprecated WktStr --- query-engine/connectors/sql-query-connector/src/row.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/query-engine/connectors/sql-query-connector/src/row.rs b/query-engine/connectors/sql-query-connector/src/row.rs index 3099986a4adf..97f7f80904dc 100644 --- a/query-engine/connectors/sql-query-connector/src/row.rs +++ b/query-engine/connectors/sql-query-connector/src/row.rs @@ -2,7 +2,7 @@ use crate::{column_metadata::ColumnMetadata, error::SqlError, geometry::trim_red use bigdecimal::{BigDecimal, FromPrimitive, ToPrimitive}; use chrono::{DateTime, NaiveDate, Utc}; use connector_interface::{coerce_null_to_zero_value, AggregationResult, AggregationSelection}; -use geozero::{wkt::WktStr, ToJson}; +use geozero::{wkt::Wkt, ToJson}; use quaint::{connector::ResultRow, Value, ValueType}; use query_structure::{ConversionFailure, FieldArity, PrismaValue, Record, TypeIdentifier}; use serde_json::json; @@ -305,7 +305,7 @@ fn row_value_to_prisma_value(p_value: Value, meta: ColumnMetadata<'_>) -> Result // and return an EWKT string instead. We differentiate the two by checking the first character. let (srid, wkt) = geom.split_once(";").unwrap(); let srid = &srid[5..]; - let mut geojson = WktStr(wkt) + let mut geojson = Wkt(wkt) .to_json() .map_err(|_| create_error(&p_value))? .parse::()?; From 77f8b0aa2375fef30a1ae048ac5f002e53f789a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 7 Oct 2024 10:05:12 +0200 Subject: [PATCH 080/103] Fix Android build --- quaint/src/geometry.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/quaint/src/geometry.rs b/quaint/src/geometry.rs index f1adac9a66ef..06b3f817ffa1 100644 --- a/quaint/src/geometry.rs +++ b/quaint/src/geometry.rs @@ -1,3 +1,4 @@ +#[allow(dead_code)] pub fn get_geometry_srid(geom: &geojson::Geometry) -> Option { geom.foreign_members .as_ref()? From 33836bce0809e81794675a3d2162ec3ad49c6ac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 7 Oct 2024 10:31:34 +0200 Subject: [PATCH 081/103] Update shema-engine CI runner --- .github/workflows/test-schema-engine.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/test-schema-engine.yml b/.github/workflows/test-schema-engine.yml index 177870ac8b49..2cff964c1c9b 100644 --- a/.github/workflows/test-schema-engine.yml +++ b/.github/workflows/test-schema-engine.yml @@ -109,9 +109,7 @@ jobs: is_vitess: true single_threaded: true - runs-on: "ubuntu-20.04" - # TODO: Replace with the following once `prisma@5.20.0` is released. - # runs-on: "ubuntu-${{ matrix.database.ubuntu || 'latest' }}" + runs-on: "ubuntu-${{ matrix.database.ubuntu || 'latest' }}" steps: - uses: actions/checkout@v4 - uses: actions-rust-lang/setup-rust-toolchain@v1 From 2a666083f6d86c8aa0f1ea223332ba80716845d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 7 Oct 2024 10:35:58 +0200 Subject: [PATCH 082/103] Try ubuntu latest for mssql query engine tests CI --- .github/workflows/test-query-engine.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/test-query-engine.yml b/.github/workflows/test-query-engine.yml index 807b6d10ccab..66c4095a4a7d 100644 --- a/.github/workflows/test-query-engine.yml +++ b/.github/workflows/test-query-engine.yml @@ -127,7 +127,6 @@ jobs: version: "2019" - name: "mssql_2017" version: "2017" - ubuntu: "20.04" uses: ./.github/workflows/test-query-engine-template.yml name: mssql ${{ matrix.database.version }} with: From 5060a30f73a4a4f4d3013d485ff339e28974ef89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 7 Oct 2024 11:11:13 +0200 Subject: [PATCH 083/103] Revert schema engine tests CI runner --- .github/workflows/test-query-engine.yml | 1 + .github/workflows/test-schema-engine.yml | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-query-engine.yml b/.github/workflows/test-query-engine.yml index 66c4095a4a7d..807b6d10ccab 100644 --- a/.github/workflows/test-query-engine.yml +++ b/.github/workflows/test-query-engine.yml @@ -127,6 +127,7 @@ jobs: version: "2019" - name: "mssql_2017" version: "2017" + ubuntu: "20.04" uses: ./.github/workflows/test-query-engine-template.yml name: mssql ${{ matrix.database.version }} with: diff --git a/.github/workflows/test-schema-engine.yml b/.github/workflows/test-schema-engine.yml index 2cff964c1c9b..177870ac8b49 100644 --- a/.github/workflows/test-schema-engine.yml +++ b/.github/workflows/test-schema-engine.yml @@ -109,7 +109,9 @@ jobs: is_vitess: true single_threaded: true - runs-on: "ubuntu-${{ matrix.database.ubuntu || 'latest' }}" + runs-on: "ubuntu-20.04" + # TODO: Replace with the following once `prisma@5.20.0` is released. + # runs-on: "ubuntu-${{ matrix.database.ubuntu || 'latest' }}" steps: - uses: actions/checkout@v4 - uses: actions-rust-lang/setup-rust-toolchain@v1 From 5c1049158843a0ce27e8cba4e9d7a1ef82bc8d65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 7 Oct 2024 11:14:27 +0200 Subject: [PATCH 084/103] Disable spatialite schema engine tests for now as Spatialite >=5.0.0 is required which only ships with Ubuntu 22.04 --- .github/workflows/test-schema-engine.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-schema-engine.yml b/.github/workflows/test-schema-engine.yml index 177870ac8b49..ff9566654add 100644 --- a/.github/workflows/test-schema-engine.yml +++ b/.github/workflows/test-schema-engine.yml @@ -101,8 +101,8 @@ jobs: url: "postgresql://prisma@localhost:26257" - name: sqlite url: sqlite - - name: spatialite - url: sqlite + # - name: spatialite + # url: sqlite - name: vitess_8_0 url: "mysql://root:prisma@localhost:33807/test" shadow_database_url: "mysql://root:prisma@localhost:33808/shadow" From da0f8e6f67598534199128e596165c5712e6dad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 7 Oct 2024 11:16:43 +0200 Subject: [PATCH 085/103] Slight quaint refactor --- quaint/src/ast/values.rs | 8 ++++---- quaint/src/visitor/mysql.rs | 2 +- quaint/src/visitor/postgres.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/quaint/src/ast/values.rs b/quaint/src/ast/values.rs index 2ea069860206..a1232597918f 100644 --- a/quaint/src/ast/values.rs +++ b/quaint/src/ast/values.rs @@ -640,8 +640,8 @@ impl<'a> fmt::Display for ValueType<'a> { ValueType::DateTime(val) => val.map(|v| write!(f, "\"{v}\"")), ValueType::Date(val) => val.map(|v| write!(f, "\"{v}\"")), ValueType::Time(val) => val.map(|v| write!(f, "\"{v}\"")), - ValueType::Geometry(val) => val.as_ref().map(|v| write!(f, "\"{v}\"")), - ValueType::Geography(val) => val.as_ref().map(|v| write!(f, "\"{v}\"")), + ValueType::Geometry(val) => val.as_ref().map(|v| write!(f, "{v}")), + ValueType::Geography(val) => val.as_ref().map(|v| write!(f, "{v}")), }; match res { @@ -700,8 +700,8 @@ impl<'a> From> for serde_json::Value { ValueType::DateTime(dt) => dt.map(|dt| serde_json::Value::String(dt.to_rfc3339())), ValueType::Date(date) => date.map(|date| serde_json::Value::String(format!("{date}"))), ValueType::Time(time) => time.map(|time| serde_json::Value::String(format!("{time}"))), - ValueType::Geometry(g) => g.map(|g| serde_json::Value::String(g.to_string())), - ValueType::Geography(g) => g.map(|g| serde_json::Value::String(g.to_string())), + ValueType::Geometry(g) => g.map(|g| geojson::GeoJson::Geometry(g).into()), + ValueType::Geography(g) => g.map(|g| geojson::GeoJson::Geometry(g).into()), }; match res { diff --git a/quaint/src/visitor/mysql.rs b/quaint/src/visitor/mysql.rs index 0e2a3eadeab1..1eca4ccc26a6 100644 --- a/quaint/src/visitor/mysql.rs +++ b/quaint/src/visitor/mysql.rs @@ -719,7 +719,7 @@ impl<'a> Visitor<'a> for Mysql<'a> { fn visit_parameterized_geometry(&mut self, geometry: geojson::Geometry) -> visitor::Result { self.surround_with("ST_GeomFromGeoJSON(", ")", |ref mut s| { - s.visit_expression(geometry.to_string().into()) + s.visit_parameterized(geometry.to_string().into()) }) } diff --git a/quaint/src/visitor/postgres.rs b/quaint/src/visitor/postgres.rs index 5ea55ea0221b..3c150ed7bae1 100644 --- a/quaint/src/visitor/postgres.rs +++ b/quaint/src/visitor/postgres.rs @@ -839,7 +839,7 @@ impl<'a> Visitor<'a> for Postgres<'a> { self.surround_with("ST_SetSRID(", ")", |s| { s.visit_geometry_from_geojson(geometry.to_string(), srid)?; s.write(",")?; - s.visit_expression(srid.into())?; + s.visit_parameterized(srid.into())?; Ok(()) }) } From bf506e94147fb3a4706f9a81e6567d513454fd5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 7 Oct 2024 11:34:31 +0200 Subject: [PATCH 086/103] Revert query-engine tests CI runner update and disable spatialite tests --- .github/workflows/test-query-engine-template.yml | 4 +++- .github/workflows/test-query-engine.yml | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-query-engine-template.yml b/.github/workflows/test-query-engine-template.yml index 87a5ff543923..7d884d640368 100644 --- a/.github/workflows/test-query-engine-template.yml +++ b/.github/workflows/test-query-engine-template.yml @@ -49,7 +49,9 @@ jobs: PRISMA_ENGINE_PROTOCOL: ${{ matrix.engine_protocol }} PRISMA_RELATION_LOAD_STRATEGY: ${{ matrix.relation_load_strategy }} - runs-on: "ubuntu-${{ inputs.ubuntu }}" + runs-on: "ubuntu-20.04" + # TODO: Replace with the following once `prisma@5.20.0` is released. + # runs-on: "ubuntu-${{ inputs.ubuntu }}" steps: - uses: actions/checkout@v4 - uses: actions-rust-lang/setup-rust-toolchain@v1 diff --git a/.github/workflows/test-query-engine.yml b/.github/workflows/test-query-engine.yml index 807b6d10ccab..838fb435616c 100644 --- a/.github/workflows/test-query-engine.yml +++ b/.github/workflows/test-query-engine.yml @@ -144,8 +144,8 @@ jobs: database: - name: "sqlite" version: "3" - - name: "spatialite" - version: "3-spatialite" + # - name: "spatialite" + # version: "3-spatialite" uses: ./.github/workflows/test-query-engine-template.yml name: sqlite ${{ matrix.database.version }} with: From 362a665d2956dc7132b3285c1e5b98bf700d5e51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 7 Oct 2024 11:56:35 +0200 Subject: [PATCH 087/103] CI workflow yaml indentation --- .github/workflows/test-query-engine-template.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-query-engine-template.yml b/.github/workflows/test-query-engine-template.yml index 7d884d640368..fe9b42e6fd5c 100644 --- a/.github/workflows/test-query-engine-template.yml +++ b/.github/workflows/test-query-engine-template.yml @@ -50,8 +50,8 @@ jobs: PRISMA_RELATION_LOAD_STRATEGY: ${{ matrix.relation_load_strategy }} runs-on: "ubuntu-20.04" - # TODO: Replace with the following once `prisma@5.20.0` is released. - # runs-on: "ubuntu-${{ inputs.ubuntu }}" + # TODO: Replace with the following once `prisma@5.20.0` is released. + # runs-on: "ubuntu-${{ inputs.ubuntu }}" steps: - uses: actions/checkout@v4 - uses: actions-rust-lang/setup-rust-toolchain@v1 From ee0a985aef8a585c5e358ea0e2adec0f0e009af5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 7 Oct 2024 13:13:12 +0200 Subject: [PATCH 088/103] No idea why QE tests are failing now --- .github/workflows/test-query-engine-template.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/test-query-engine-template.yml b/.github/workflows/test-query-engine-template.yml index fe9b42e6fd5c..87a5ff543923 100644 --- a/.github/workflows/test-query-engine-template.yml +++ b/.github/workflows/test-query-engine-template.yml @@ -49,9 +49,7 @@ jobs: PRISMA_ENGINE_PROTOCOL: ${{ matrix.engine_protocol }} PRISMA_RELATION_LOAD_STRATEGY: ${{ matrix.relation_load_strategy }} - runs-on: "ubuntu-20.04" - # TODO: Replace with the following once `prisma@5.20.0` is released. - # runs-on: "ubuntu-${{ inputs.ubuntu }}" + runs-on: "ubuntu-${{ inputs.ubuntu }}" steps: - uses: actions/checkout@v4 - uses: actions-rust-lang/setup-rust-toolchain@v1 From 4210df8b0a6123ed22f835731baedcc5028f7d57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 7 Oct 2024 13:51:53 +0200 Subject: [PATCH 089/103] CI now fails for mssql-2017 as it is the only job running on 20.04... so let's try it with latest instead. --- .github/workflows/test-query-engine.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/test-query-engine.yml b/.github/workflows/test-query-engine.yml index 838fb435616c..4c2531eec887 100644 --- a/.github/workflows/test-query-engine.yml +++ b/.github/workflows/test-query-engine.yml @@ -127,7 +127,6 @@ jobs: version: "2019" - name: "mssql_2017" version: "2017" - ubuntu: "20.04" uses: ./.github/workflows/test-query-engine-template.yml name: mssql ${{ matrix.database.version }} with: From 044ec3d4f21126dd92770b3ac259f970f682bc7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Tue, 8 Oct 2024 23:37:33 +0200 Subject: [PATCH 090/103] Simplify SRID handling in quaint by making 4326 the default everywhere --- .github/workflows/test-query-engine.yml | 4 +- .../cockroach_datamodel_connector.rs | 10 +-- .../src/builtin_connectors/geometry.rs | 22 ++++-- .../postgres_datamodel_connector.rs | 10 +-- .../sqlite_datamodel_connector.rs | 7 +- .../tests/types/cockroachdb_native_types.rs | 2 +- psl/psl/tests/types/postgres_native_types.rs | 2 +- psl/psl/tests/types/sqlite_native_types.rs | 2 +- quaint/src/ast/column.rs | 4 +- quaint/src/geometry.rs | 14 ++-- quaint/src/visitor/mssql.rs | 4 +- quaint/src/visitor/postgres.rs | 39 +++++------ quaint/src/visitor/sqlite.rs | 35 +++++++--- .../sql-query-connector/src/geometry.rs | 18 ----- .../connectors/sql-query-connector/src/lib.rs | 1 - .../src/model_extensions/scalar_field.rs | 49 +++---------- .../connectors/sql-query-connector/src/row.rs | 21 +++++- .../tests/native_types/postgres.rs | 68 +++++++++---------- .../tests/native_types/sqlite.rs | 2 +- .../sql-schema-describer/src/postgres.rs | 5 +- .../sql-schema-describer/src/sqlite.rs | 9 +-- 21 files changed, 152 insertions(+), 176 deletions(-) delete mode 100644 query-engine/connectors/sql-query-connector/src/geometry.rs diff --git a/.github/workflows/test-query-engine.yml b/.github/workflows/test-query-engine.yml index 4c2531eec887..66c4095a4a7d 100644 --- a/.github/workflows/test-query-engine.yml +++ b/.github/workflows/test-query-engine.yml @@ -143,8 +143,8 @@ jobs: database: - name: "sqlite" version: "3" - # - name: "spatialite" - # version: "3-spatialite" + - name: "spatialite" + version: "3-spatialite" uses: ./.github/workflows/test-query-engine-template.yml name: sqlite ${{ matrix.database.version }} with: 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 088e51cc7e27..676a55c6a5ae 100644 --- a/psl/psl-core/src/builtin_connectors/cockroach_datamodel_connector.rs +++ b/psl/psl-core/src/builtin_connectors/cockroach_datamodel_connector.rs @@ -23,10 +23,7 @@ use enumflags2::BitFlags; use lsp_types::{CompletionItem, CompletionItemKind, CompletionList}; use std::borrow::Cow; -use super::{ - completions, - geometry::{GeometryParams, GeometryType}, -}; +use super::{completions, geometry::GeometryParams}; const CONSTRAINT_SCOPES: &[ConstraintScope] = &[ConstraintScope::ModelPrimaryKeyKeyIndexForeignKey]; @@ -81,10 +78,7 @@ const SCALAR_TYPE_DEFAULTS: &[(ScalarType, CockroachType)] = &[ (ScalarType::Json, CockroachType::JsonB), ( ScalarType::Geometry, - CockroachType::Geometry(Some(GeometryParams { - type_: GeometryType::Geometry, - srid: 0, - })), + CockroachType::Geometry(Some(GeometryParams::default())), ), ]; diff --git a/psl/psl-core/src/builtin_connectors/geometry.rs b/psl/psl-core/src/builtin_connectors/geometry.rs index b3ef5d4de6d9..4e8d4be6238a 100644 --- a/psl/psl-core/src/builtin_connectors/geometry.rs +++ b/psl/psl-core/src/builtin_connectors/geometry.rs @@ -1,15 +1,23 @@ use std::{fmt, str::FromStr}; -#[derive(Debug, Default, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq)] pub struct GeometryParams { pub type_: GeometryType, pub srid: i32, } +impl GeometryParams { + pub const fn default() -> Self { + Self { + type_: GeometryType::Geometry, + srid: 4326, + } + } +} + #[repr(u32)] -#[derive(Debug, Default, Clone, Copy, PartialEq, PartialOrd)] +#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] pub enum GeometryType { - #[default] Geometry = 0, Point = 1, LineString = 2, @@ -140,12 +148,14 @@ impl crate::datamodel_connector::NativeTypeArguments for GeometryParams { fn from_parts(parts: &[String]) -> Option { // GeometryParams is used in Postgres, Cockroach and SQlite. For the three of them, - // the database type for the primsa Geometry type is db.Geometry(Geometry, 0). + // the database type for the primsa Geometry type is db.Geometry(Geometry, 4326). // We don't want to force the users to think about what SRID they should choose // in case they're only interested in setting the geometry type, so in such - // case we manually set the SRID to 0 here. + // case we manually set the SRID to 4326 here. match parts { - [geom] => GeometryType::from_str(geom).ok().map(|ty| Self { type_: ty, srid: 0 }), + [geom] => GeometryType::from_str(geom) + .ok() + .map(|ty| Self { type_: ty, srid: 4326 }), [geom, srid] => GeometryType::from_str(geom) .ok() .and_then(|ty| srid.parse().ok().map(|srid| Self { type_: ty, srid })), diff --git a/psl/psl-core/src/builtin_connectors/postgres_datamodel_connector.rs b/psl/psl-core/src/builtin_connectors/postgres_datamodel_connector.rs index d8ced5ca0159..19ce57147dcd 100644 --- a/psl/psl-core/src/builtin_connectors/postgres_datamodel_connector.rs +++ b/psl/psl-core/src/builtin_connectors/postgres_datamodel_connector.rs @@ -19,10 +19,7 @@ use lsp_types::{CompletionItem, CompletionItemKind, CompletionList, InsertTextFo use std::{borrow::Cow, collections::HashMap}; use PostgresType::*; -use super::{ - completions, - geometry::{GeometryParams, GeometryType}, -}; +use super::{completions, geometry::GeometryParams}; const CONSTRAINT_SCOPES: &[ConstraintScope] = &[ ConstraintScope::GlobalPrimaryKeyKeyIndex, @@ -92,10 +89,7 @@ const SCALAR_TYPE_DEFAULTS: &[(ScalarType, PostgresType)] = &[ (ScalarType::Json, PostgresType::JsonB), ( ScalarType::Geometry, - PostgresType::Geometry(Some(GeometryParams { - type_: GeometryType::Geometry, - srid: 0, - })), + PostgresType::Geometry(Some(GeometryParams::default())), ), ]; diff --git a/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs b/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs index 6b90abb98463..409c050de272 100644 --- a/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs +++ b/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs @@ -11,7 +11,7 @@ use crate::{ }; use enumflags2::BitFlags; -use super::geometry::{GeometryParams, GeometryType}; +use super::geometry::GeometryParams; const CONSTRAINT_SCOPES: &[ConstraintScope] = &[ConstraintScope::GlobalKeyIndex]; pub const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(ConnectorCapability::{ @@ -39,10 +39,7 @@ pub const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(Conne const SCALAR_TYPE_DEFAULTS: &[(ScalarType, SQLiteType)] = &[( ScalarType::Geometry, - SQLiteType::Geometry(Some(GeometryParams { - type_: GeometryType::Geometry, - srid: 0, - })), + SQLiteType::Geometry(Some(GeometryParams::default())), )]; pub struct SqliteDatamodelConnector; diff --git a/psl/psl/tests/types/cockroachdb_native_types.rs b/psl/psl/tests/types/cockroachdb_native_types.rs index 609e38d7296d..6e183fd3be6f 100644 --- a/psl/psl/tests/types/cockroachdb_native_types.rs +++ b/psl/psl/tests/types/cockroachdb_native_types.rs @@ -184,7 +184,7 @@ fn cockroach_specific_native_types_are_valid() { timesttzcol DateTime @db.Timestamptz uuidcol String @db.Uuid varbitcol String @db.VarBit(200) - geomcol1 Geometry @db.Geometry(Geometry, 4326) + geomcol1 Geometry geomcol2 Geometry @db.Geometry(GeometryZ, 4326) geomcol3 Geometry @db.Geometry(Point, 4326) geomcol4 Geometry @db.Geometry(PointZ, 4326) diff --git a/psl/psl/tests/types/postgres_native_types.rs b/psl/psl/tests/types/postgres_native_types.rs index cfdbc1eb2ac3..a57fa095b9a7 100644 --- a/psl/psl/tests/types/postgres_native_types.rs +++ b/psl/psl/tests/types/postgres_native_types.rs @@ -243,7 +243,7 @@ fn postgis_specific_native_types_are_valid() { model NativeTypesTest { id Int @id - geom_01 Geometry @db.Geometry(Geometry, 4326) + geom_01 Geometry geom_02 Geometry @db.Geometry(GeometryZ, 4326) geom_03 Geometry @db.Geometry(Point, 4326) geom_04 Geometry @db.Geometry(PointZ, 4326) diff --git a/psl/psl/tests/types/sqlite_native_types.rs b/psl/psl/tests/types/sqlite_native_types.rs index 579bcd01ba93..e1dc87788839 100644 --- a/psl/psl/tests/types/sqlite_native_types.rs +++ b/psl/psl/tests/types/sqlite_native_types.rs @@ -11,7 +11,7 @@ fn sqlite_specific_native_types_are_valid() { model NativeTypesTest { id Int @id - geomcol1 Geometry @db.Geometry(Geometry, 4326) + geomcol1 Geometry geomcol2 Geometry @db.Geometry(GeometryZ, 4326) geomcol3 Geometry @db.Geometry(Point, 4326) geomcol4 Geometry @db.Geometry(PointZ, 4326) diff --git a/quaint/src/ast/column.rs b/quaint/src/ast/column.rs index 022548c4e43f..75aef4a5c029 100644 --- a/quaint/src/ast/column.rs +++ b/quaint/src/ast/column.rs @@ -20,8 +20,8 @@ pub enum TypeFamily { Boolean, Uuid, DateTime, - Geometry(Option), - Geography(Option), + Geometry, + Geography, Decimal(Option<(u8, u8)>), Bytes(Option), } diff --git a/quaint/src/geometry.rs b/quaint/src/geometry.rs index 06b3f817ffa1..6eb31797eac9 100644 --- a/quaint/src/geometry.rs +++ b/quaint/src/geometry.rs @@ -1,13 +1,19 @@ #[allow(dead_code)] -pub fn get_geometry_srid(geom: &geojson::Geometry) -> Option { - geom.foreign_members - .as_ref()? +pub(crate) fn get_geometry_crs(geojson: &serde_json::Map) -> Option<&str> { + geojson .get("crs")? .as_object()? .get("properties")? .as_object()? .get("name")? - .as_str()? + .as_str() +} + +#[allow(dead_code)] +pub fn get_geometry_srid(geom: &geojson::Geometry) -> Option { + geom.foreign_members + .as_ref() + .and_then(get_geometry_crs)? .rsplit_once(":")? .1 .parse() diff --git a/quaint/src/visitor/mssql.rs b/quaint/src/visitor/mssql.rs index e08939afe94c..acd6f65358f5 100644 --- a/quaint/src/visitor/mssql.rs +++ b/quaint/src/visitor/mssql.rs @@ -80,8 +80,8 @@ impl<'a> Mssql<'a> { TypeFamily::Boolean => self.write("BIT"), TypeFamily::Uuid => self.write("UNIQUEIDENTIFIER"), TypeFamily::DateTime => self.write("DATETIMEOFFSET"), - TypeFamily::Geometry(_) => self.write("GEOMETRY"), - TypeFamily::Geography(_) => self.write("GEOGRAPHY"), + TypeFamily::Geometry => self.write("GEOMETRY"), + TypeFamily::Geography => self.write("GEOGRAPHY"), TypeFamily::Bytes(len) => { self.write("VARBINARY(")?; match len { diff --git a/quaint/src/visitor/postgres.rs b/quaint/src/visitor/postgres.rs index 3c150ed7bae1..20e9fc975771 100644 --- a/quaint/src/visitor/postgres.rs +++ b/quaint/src/visitor/postgres.rs @@ -51,18 +51,17 @@ impl<'a> Postgres<'a> { S: Into>, { // We shouldn't have to do that but are forced to because CockroachDb doesn't parse the CRS information - // from the geojson string like PostGIS does. (https://github.com/cockroachdb/cockroach/issues/132046) + // from the geojson string like PostGIS does. (https://github.com/cockroachdb/cockroach/issues/132046). + // Also, older versions of PostGIS don't set the resulting geometry SRID to 4326 by default. - if let Some(srid) = srid { - self.surround_with("ST_SetSRID(", ")", |s| { - s.visit_geometry(geometry.into())?; - s.write(",")?; - s.visit_expression(srid.into())?; - Ok(()) - }) - } else { - self.visit_geometry(geometry.into()) - } + self.surround_with("ST_SetSRID(", ")", |s| { + s.surround_with("ST_GeomFromGeoJSON(", ")", |ref mut s| { + s.visit_expression(geometry.into()) + })?; + s.write(",")?; + s.visit_expression(srid.map(Into::into).unwrap_or(4326.into()))?; + Ok(()) + }) } fn visit_geography_from_geojson(&mut self, geometry: G, srid: Option) -> visitor::Result @@ -73,10 +72,6 @@ impl<'a> Postgres<'a> { self.visit_geometry_from_geojson(geometry, srid)?; self.write("::geography") } - - fn visit_geometry(&mut self, geometry: Expression<'a>) -> visitor::Result { - self.surround_with("ST_GeomFromGeoJSON(", ")", |ref mut s| s.visit_expression(geometry)) - } } impl<'a> Visitor<'a> for Postgres<'a> { @@ -836,12 +831,9 @@ impl<'a> Visitor<'a> for Postgres<'a> { fn visit_parameterized_geometry(&mut self, geometry: geojson::Geometry) -> visitor::Result { let srid = get_geometry_srid(&geometry); - self.surround_with("ST_SetSRID(", ")", |s| { - s.visit_geometry_from_geojson(geometry.to_string(), srid)?; - s.write(",")?; - s.visit_parameterized(srid.into())?; - Ok(()) - }) + self.visit_geometry_from_geojson(geometry.to_string(), srid)?; + + Ok(()) } fn visit_parameterized_geography(&mut self, geometry: geojson::Geometry) -> visitor::Result { @@ -1282,7 +1274,10 @@ mod tests { let geojson = r#"{"type":"Point","coordinates":[1.0,2.0]}"#; let geom = geojson.parse::().unwrap(); let (sql, params) = Postgres::build(Select::default().value(Value::geography(geom).raw())).unwrap(); - assert_eq!(format!("SELECT ST_GeomFromGeoJSON('{geojson}')::geography"), sql); + assert_eq!( + format!("SELECT ST_SetSRID(ST_GeomFromGeoJSON('{geojson}'),4326)::geography"), + sql + ); assert!(params.is_empty()); } diff --git a/quaint/src/visitor/sqlite.rs b/quaint/src/visitor/sqlite.rs index 655e712c4d0e..f42bd6a6dea6 100644 --- a/quaint/src/visitor/sqlite.rs +++ b/quaint/src/visitor/sqlite.rs @@ -1,6 +1,7 @@ use crate::{ ast::*, error::{Error, ErrorKind}, + geometry::get_geometry_srid, visitor::{self, Visitor}, }; @@ -34,11 +35,20 @@ impl<'a> Sqlite<'a> { Ok(()) } - fn visit_geometry_from_geojson(&mut self, geometry: G) -> visitor::Result + fn visit_geometry_from_geojson(&mut self, geometry: G, srid: Option) -> visitor::Result where G: Into>, + S: Into>, { - self.surround_with("GeomFromGeoJSON(", ")", |ref mut s| s.visit_expression(geometry.into())) + // This is required since contrary to other vendors, Spatialite GeomFromGeoJSON + // doesn't return a geometry with SRID=4326 but with SRID=-1. + + self.surround_with("SetSRID(", ")", |s| { + s.surround_with("GeomFromGeoJSON(", ")", |ref mut s| s.visit_expression(geometry.into()))?; + s.write(",")?; + s.visit_expression(srid.map(Into::into).unwrap_or(4326.into()))?; + Ok(()) + }) } } @@ -144,12 +154,14 @@ impl<'a> Visitor<'a> for Sqlite<'a> { ValueType::Date(date) => date.map(|date| self.write(format!("'{date}'"))), ValueType::Time(time) => time.map(|time| self.write(format!("'{time}'"))), ValueType::Xml(cow) => cow.as_ref().map(|cow| self.write(format!("'{cow}'"))), - ValueType::Geometry(g) => g - .as_ref() - .map(|g| self.visit_geometry_from_geojson(g.to_string().raw())), - ValueType::Geography(g) => g - .as_ref() - .map(|g| self.visit_geometry_from_geojson(g.to_string().raw())), + ValueType::Geometry(geometry) => geometry.as_ref().map(|geometry| { + let srid = get_geometry_srid(geometry); + self.visit_geometry_from_geojson(geometry.to_string().raw(), srid.map(IntoRaw::raw)) + }), + ValueType::Geography(geometry) => geometry.as_ref().map(|geometry| { + let srid = get_geometry_srid(geometry); + self.visit_geometry_from_geojson(geometry.to_string().raw(), srid.map(IntoRaw::raw)) + }), }; match res { @@ -508,11 +520,12 @@ impl<'a> Visitor<'a> for Sqlite<'a> { } fn visit_parameterized_geometry(&mut self, geometry: geojson::Geometry) -> visitor::Result { - self.visit_geometry_from_geojson(geometry.to_string()) + let srid = get_geometry_srid(&geometry); + self.visit_geometry_from_geojson(geometry.to_string(), srid) } fn visit_parameterized_geography(&mut self, geometry: geojson::Geometry) -> visitor::Result { - self.visit_geometry_from_geojson(geometry.to_string()) + self.visit_parameterized_geometry(geometry) } } @@ -1074,7 +1087,7 @@ mod tests { let geojson = r#"{"type":"Point","coordinates":[1.0,2.0]}"#; let geom = geojson.parse::().unwrap(); let (sql, params) = Sqlite::build(Select::default().value(Value::geometry(geom).raw())).unwrap(); - assert_eq!(format!("SELECT GeomFromGeoJSON('{geojson}')"), sql); + assert_eq!(format!("SELECT SetSRID(GeomFromGeoJSON('{geojson}'),4326)"), sql); assert!(params.is_empty()); } diff --git a/query-engine/connectors/sql-query-connector/src/geometry.rs b/query-engine/connectors/sql-query-connector/src/geometry.rs deleted file mode 100644 index 0f0e358270d4..000000000000 --- a/query-engine/connectors/sql-query-connector/src/geometry.rs +++ /dev/null @@ -1,18 +0,0 @@ -use serde_json::{Map, Value}; - -pub(crate) fn get_geometry_crs(geojson: &Map) -> Option<&str> { - geojson - .get("crs")? - .as_object()? - .get("properties")? - .as_object()? - .get("name")? - .as_str() -} - -pub(crate) fn trim_redundent_crs(geojson: &mut Map) { - let crs = get_geometry_crs(geojson); - if matches!(crs, Some("EPSG:4326" | "EPSG:0")) { - geojson.remove("crs"); - }; -} diff --git a/query-engine/connectors/sql-query-connector/src/lib.rs b/query-engine/connectors/sql-query-connector/src/lib.rs index 9633c3764712..9bd6c2d7f211 100644 --- a/query-engine/connectors/sql-query-connector/src/lib.rs +++ b/query-engine/connectors/sql-query-connector/src/lib.rs @@ -7,7 +7,6 @@ mod cursor_condition; mod database; mod error; mod filter; -mod geometry; mod join_utils; mod model_extensions; mod nested_aggregations; diff --git a/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs b/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs index b108de5450a1..d5bc9b5010e0 100644 --- a/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs +++ b/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs @@ -1,4 +1,4 @@ -use crate::{context::Context, geometry::get_geometry_crs}; +use crate::context::Context; use chrono::Utc; use geojson::Geometry; use prisma_value::PrismaValue; @@ -7,7 +7,6 @@ use quaint::{ prelude::{EnumVariant, TypeDataLength, TypeFamily}, }; use query_structure::{ScalarField, TypeIdentifier}; -use serde_json::json; pub(crate) trait ScalarFieldExt { fn value<'a>(&self, pv: PrismaValue, ctx: &Context<'_>) -> Value<'a>; @@ -56,31 +55,10 @@ impl ScalarFieldExt for ScalarField { (PrismaValue::Bytes(b), _) => Value::bytes(b), (PrismaValue::Object(_), _) => unimplemented!(), (PrismaValue::GeoJson(s), _) => { - let mut geometry = s.parse::().unwrap(); - let column_type = self.type_family(); - let column_srid = match column_type { - TypeFamily::Geography(srid) => srid, - TypeFamily::Geometry(srid) => srid, - _ => unreachable!(), - }; - // To facilitate geometry insertion, We manually set the GeoJSON CRS field - // to the column constrained SRID if the latter is set to 4326 (the default) - // or "unknown" (0 or -1). If there is no contraint at all, set it to 4326 - // anyway for consistency's sake, and also because SQL Server requires one - // in order to create a geometry - let geometry_crs = geometry.foreign_members.as_ref().and_then(|m| get_geometry_crs(m)); - if geometry_crs.is_none() && matches!(column_srid, None | Some(-1 | 0 | 4326)) { - let srid = column_srid.unwrap_or(4326); - let mut m = serde_json::Map::new(); - m.insert( - "crs".to_string(), - json!({"type": "name", "properties": {"name": format!("EPSG:{srid}")}}), - ); - geometry.foreign_members = Some(m); - }; - match column_type { - TypeFamily::Geography(_) => Value::geography(geometry), - TypeFamily::Geometry(_) => Value::geometry(geometry), + let geometry = s.parse::().unwrap(); + match self.type_family() { + TypeFamily::Geography => Value::geography(geometry), + TypeFamily::Geometry => Value::geometry(geometry), _ => unreachable!(), } } @@ -137,19 +115,10 @@ impl ScalarFieldExt for ScalarField { TypeIdentifier::DateTime => TypeFamily::DateTime, TypeIdentifier::Bytes => TypeFamily::Text(parse_scalar_length(self)), TypeIdentifier::Geometry => { - let type_info = self.native_type().map(|nt| { - let name = nt.name(); - let srid = match nt.args().as_slice() { - [srid] => srid.parse::().ok(), - [_type, srid] => srid.parse::().ok(), - _ => None, - }; - (name, srid) - }); - match type_info { - Some(("Geography", srid)) => TypeFamily::Geography(srid), - Some((_, srid)) => TypeFamily::Geometry(srid), - _ => TypeFamily::Geometry(None), + let type_name = self.native_type().map(|nt| nt.name()); + match type_name { + Some("Geography") => TypeFamily::Geography, + _ => TypeFamily::Geometry, } } TypeIdentifier::Unsupported => unreachable!("No unsupported field should reach that path"), diff --git a/query-engine/connectors/sql-query-connector/src/row.rs b/query-engine/connectors/sql-query-connector/src/row.rs index 97f7f80904dc..08ea41c174fe 100644 --- a/query-engine/connectors/sql-query-connector/src/row.rs +++ b/query-engine/connectors/sql-query-connector/src/row.rs @@ -1,11 +1,11 @@ -use crate::{column_metadata::ColumnMetadata, error::SqlError, geometry::trim_redundent_crs, value::to_prisma_value}; +use crate::{column_metadata::ColumnMetadata, error::SqlError, value::to_prisma_value}; use bigdecimal::{BigDecimal, FromPrimitive, ToPrimitive}; use chrono::{DateTime, NaiveDate, Utc}; use connector_interface::{coerce_null_to_zero_value, AggregationResult, AggregationSelection}; use geozero::{wkt::Wkt, ToJson}; use quaint::{connector::ResultRow, Value, ValueType}; use query_structure::{ConversionFailure, FieldArity, PrismaValue, Record, TypeIdentifier}; -use serde_json::json; +use serde_json::{json, Map, Value as JsonValue}; use std::{io, str::FromStr}; use uuid::Uuid; @@ -376,6 +376,23 @@ pub(crate) fn big_decimal_to_i64(dec: BigDecimal, to: &'static str) -> Result) -> Option<&str> { + geojson + .get("crs")? + .as_object()? + .get("properties")? + .as_object()? + .get("name")? + .as_str() +} + +pub(crate) fn trim_redundent_crs(geojson: &mut Map) { + let crs = get_geometry_crs(geojson); + if matches!(crs, Some("EPSG:4326")) { + geojson.remove("crs"); + }; +} + #[cfg(test)] mod test { use super::*; 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 5429481258c3..628752dd48b6 100644 --- a/schema-engine/sql-introspection-tests/tests/native_types/postgres.rs +++ b/schema-engine/sql-introspection-tests/tests/native_types/postgres.rs @@ -37,7 +37,7 @@ const TYPES: &[(&str, &str)] = &[ ]; const GEOMETRY_TYPES: &[(&str, &str)] = &[ - ("geometry", "Geometry"), + ("geometry_default", "Geometry(Geometry, 4326)"), ("geometry_srid", "Geometry(Geometry, 3857)"), ("geometry_geometry_z", "Geometry(GeometryZ)"), ("geometry_point", "Geometry(Point)"), @@ -54,22 +54,22 @@ const GEOMETRY_TYPES: &[(&str, &str)] = &[ ("geometry_multipolygon_z", "Geometry(MultiPolygonZ)"), ("geometry_geometrycollection", "Geometry(GeometryCollection)"), ("geometry_geometrycollection_z", "Geometry(GeometryCollectionZ)"), - ("geography_geometry", "Geography(Geometry, 4326)"), - ("geography_geometry_z", "Geography(GeometryZ, 4326)"), - ("geography_point", "Geography(Point, 4326)"), - ("geography_point_z", "Geography(PointZ, 4326)"), - ("geography_linestring", "Geography(LineString, 4326)"), - ("geography_linestring_z", "Geography(LineStringZ, 4326)"), - ("geography_polygon", "Geography(Polygon, 4326)"), - ("geography_polygon_z", "Geography(PolygonZ, 4326)"), - ("geography_multipoint", "Geography(MultiPoint, 4326)"), - ("geography_multipoint_z", "Geography(MultiPointZ, 4326)"), - ("geography_multilinestring", "Geography(MultiLineString, 4326)"), - ("geography_multilinestring_z", "Geography(MultiLineStringZ, 4326)"), - ("geography_multipolygon", "Geography(MultiPolygon, 4326)"), - ("geography_multipolygon_z", "Geography(MultiPolygonZ, 4326)"), - ("geography_geometrycollection", "Geography(GeometryCollection, 4326)"), - ("geography_geometrycollection_z", "Geography(GeometryCollectionZ, 4326)"), + ("geography_geometry", "Geography(Geometry, 9000)"), + ("geography_geometry_z", "Geography(GeometryZ, 9000)"), + ("geography_point", "Geography(Point, 9000)"), + ("geography_point_z", "Geography(PointZ, 9000)"), + ("geography_linestring", "Geography(LineString, 9000)"), + ("geography_linestring_z", "Geography(LineStringZ, 9000)"), + ("geography_polygon", "Geography(Polygon, 9000)"), + ("geography_polygon_z", "Geography(PolygonZ, 9000)"), + ("geography_multipoint", "Geography(MultiPoint, 9000)"), + ("geography_multipoint_z", "Geography(MultiPointZ, 9000)"), + ("geography_multilinestring", "Geography(MultiLineString, 9000)"), + ("geography_multilinestring_z", "Geography(MultiLineStringZ, 9000)"), + ("geography_multipolygon", "Geography(MultiPolygon, 9000)"), + ("geography_multipolygon_z", "Geography(MultiPolygonZ, 9000)"), + ("geography_geometrycollection", "Geography(GeometryCollection, 9000)"), + ("geography_geometrycollection_z", "Geography(GeometryCollectionZ, 9000)"), ]; #[test_connector(tags(Postgres), exclude(PostGIS, CockroachDb))] @@ -159,7 +159,7 @@ async fn native_type_spatial_columns_feature_on(api: &mut TestApi) -> TestResult let mut types = indoc! {r#" model Spatial { id Int @id - geometry Geometry + geometry_default Geometry geometry_srid Geometry @db.Geometry(Geometry, 3857) geometry_geometry_z Geometry @db.Geometry(GeometryZ, 0) geometry_point Geometry @db.Geometry(Point, 0) @@ -176,22 +176,22 @@ async fn native_type_spatial_columns_feature_on(api: &mut TestApi) -> TestResult geometry_multipolygon_z Geometry @db.Geometry(MultiPolygonZ, 0) geometry_geometrycollection Geometry @db.Geometry(GeometryCollection, 0) geometry_geometrycollection_z Geometry @db.Geometry(GeometryCollectionZ, 0) - geography_geometry Geometry @db.Geography(Geometry, 4326) - geography_geometry_z Geometry @db.Geography(GeometryZ, 4326) - geography_point Geometry @db.Geography(Point, 4326) - geography_point_z Geometry @db.Geography(PointZ, 4326) - geography_linestring Geometry @db.Geography(LineString, 4326) - geography_linestring_z Geometry @db.Geography(LineStringZ, 4326) - geography_polygon Geometry @db.Geography(Polygon, 4326) - geography_polygon_z Geometry @db.Geography(PolygonZ, 4326) - geography_multipoint Geometry @db.Geography(MultiPoint, 4326) - geography_multipoint_z Geometry @db.Geography(MultiPointZ, 4326) - geography_multilinestring Geometry @db.Geography(MultiLineString, 4326) - geography_multilinestring_z Geometry @db.Geography(MultiLineStringZ, 4326) - geography_multipolygon Geometry @db.Geography(MultiPolygon, 4326) - geography_multipolygon_z Geometry @db.Geography(MultiPolygonZ, 4326) - geography_geometrycollection Geometry @db.Geography(GeometryCollection, 4326) - geography_geometrycollection_z Geometry @db.Geography(GeometryCollectionZ, 4326) + geography_geometry Geometry @db.Geography(Geometry, 9000) + geography_geometry_z Geometry @db.Geography(GeometryZ, 9000) + geography_point Geometry @db.Geography(Point, 9000) + geography_point_z Geometry @db.Geography(PointZ, 9000) + geography_linestring Geometry @db.Geography(LineString, 9000) + geography_linestring_z Geometry @db.Geography(LineStringZ, 9000) + geography_polygon Geometry @db.Geography(Polygon, 9000) + geography_polygon_z Geometry @db.Geography(PolygonZ, 9000) + geography_multipoint Geometry @db.Geography(MultiPoint, 9000) + geography_multipoint_z Geometry @db.Geography(MultiPointZ, 9000) + geography_multilinestring Geometry @db.Geography(MultiLineString, 9000) + geography_multilinestring_z Geometry @db.Geography(MultiLineStringZ, 9000) + geography_multipolygon Geometry @db.Geography(MultiPolygon, 9000) + geography_multipolygon_z Geometry @db.Geography(MultiPolygonZ, 9000) + geography_geometrycollection Geometry @db.Geography(GeometryCollection, 9000) + geography_geometrycollection_z Geometry @db.Geography(GeometryCollectionZ, 9000) } "#} .to_string(); diff --git a/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs b/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs index 1b759f4f232b..7a3475c9baff 100644 --- a/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs +++ b/schema-engine/sql-introspection-tests/tests/native_types/sqlite.rs @@ -32,7 +32,7 @@ async fn native_spatial_type_columns_feature_on(api: &mut TestApi) -> TestResult let expectation = expect![[r#" model User { id Int @id @default(autoincrement()) - geometry_xy Geometry? @db.Geometry(Geometry, 4326) + geometry_xy Geometry? geometry_xyz Geometry? @db.Geometry(GeometryZ, 4326) point_xy Geometry? @db.Geometry(Point, 4326) point_xyz Geometry? @db.Geometry(PointZ, 4326) diff --git a/schema-engine/sql-schema-describer/src/postgres.rs b/schema-engine/sql-schema-describer/src/postgres.rs index 21035fb53e86..425f6b3dce16 100644 --- a/schema-engine/sql-schema-describer/src/postgres.rs +++ b/schema-engine/sql-schema-describer/src/postgres.rs @@ -989,13 +989,12 @@ impl<'a> SqlSchemaDescriber<'a> { let geom_type = capture .name("type") .map(|t| GeometryType::from_str(t.as_str())) - .unwrap_or(Ok(GeometryType::default())); - let is_cockroach = circumstances.contains(Circumstances::Cockroach); + .unwrap_or(Ok(GeometryType::Geometry)); let is_geography = capture.name("class").map(|c| c.as_str() == "geography").unwrap(); let srid = capture .name("srid") .map(|v| v.as_str().parse::()) - .unwrap_or(Ok(if is_geography && !is_cockroach { 4326 } else { 0 })); + .unwrap_or(Ok(if is_geography { 4326 } else { 0 })); match (geom_type, srid) { (Ok(type_), Ok(srid)) => Some(GeometryParams { type_, srid }), _ => None, diff --git a/schema-engine/sql-schema-describer/src/sqlite.rs b/schema-engine/sql-schema-describer/src/sqlite.rs index ba0bc019f1fb..2650c0bddcd4 100644 --- a/schema-engine/sql-schema-describer/src/sqlite.rs +++ b/schema-engine/sql-schema-describer/src/sqlite.rs @@ -403,14 +403,15 @@ async fn push_columns( let column_type = row.get_expect_string("type"); let geometry_info = geometry_columns.get(&(table_name.to_lowercase(), column_name.to_lowercase())); let tpe = if let Some((type_, srid)) = geometry_info { + let params = GeometryParams { + type_: *type_, + srid: *srid, + }; ColumnType { full_data_type: column_type, family: ColumnTypeFamily::Geometry, arity, - native_type: Some(NativeTypeInstance::new(SQLiteType::Geometry(Some(GeometryParams { - type_: *type_, - srid: *srid, - })))), + native_type: Some(NativeTypeInstance::new(SQLiteType::Geometry(Some(params)))), } } else { get_column_type(column_type, arity) From 205e6727f5bdfe2da82d3ec0609ba565a831b885 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Wed, 9 Oct 2024 00:37:19 +0200 Subject: [PATCH 091/103] Make SRID mandatory in db geometry type parameters --- psl/psl-core/src/builtin_connectors/geometry.rs | 17 +++++------------ psl/psl/tests/types/cockroachdb_native_types.rs | 6 +++--- psl/psl/tests/types/sqlite_native_types.rs | 6 +++--- 3 files changed, 11 insertions(+), 18 deletions(-) diff --git a/psl/psl-core/src/builtin_connectors/geometry.rs b/psl/psl-core/src/builtin_connectors/geometry.rs index 4e8d4be6238a..61db34d901ab 100644 --- a/psl/psl-core/src/builtin_connectors/geometry.rs +++ b/psl/psl-core/src/builtin_connectors/geometry.rs @@ -142,23 +142,16 @@ impl fmt::Display for GeometryType { } impl crate::datamodel_connector::NativeTypeArguments for GeometryParams { - const DESCRIPTION: &'static str = "a geometry type and an optional srid"; + const DESCRIPTION: &'static str = "a geometry type and an srid"; const OPTIONAL_ARGUMENTS_COUNT: usize = 0; const REQUIRED_ARGUMENTS_COUNT: usize = 2; fn from_parts(parts: &[String]) -> Option { - // GeometryParams is used in Postgres, Cockroach and SQlite. For the three of them, - // the database type for the primsa Geometry type is db.Geometry(Geometry, 4326). - // We don't want to force the users to think about what SRID they should choose - // in case they're only interested in setting the geometry type, so in such - // case we manually set the SRID to 4326 here. match parts { - [geom] => GeometryType::from_str(geom) - .ok() - .map(|ty| Self { type_: ty, srid: 4326 }), - [geom, srid] => GeometryType::from_str(geom) - .ok() - .and_then(|ty| srid.parse().ok().map(|srid| Self { type_: ty, srid })), + [geom, srid] => Some(Self { + type_: GeometryType::from_str(geom).ok()?, + srid: srid.parse().ok()?, + }), _ => None, } } diff --git a/psl/psl/tests/types/cockroachdb_native_types.rs b/psl/psl/tests/types/cockroachdb_native_types.rs index 6e183fd3be6f..91c704237e99 100644 --- a/psl/psl/tests/types/cockroachdb_native_types.rs +++ b/psl/psl/tests/types/cockroachdb_native_types.rs @@ -236,16 +236,16 @@ fn should_fail_on_geometry_when_invalid_geometry_type() { model Blog { id Int @id - geom Geometry @db.Geometry(Invalid) + geom Geometry @db.Geometry(Invalid, 0) } "#}; let expectation = expect![[r#" - error: Expected a geometry type and an optional srid, but found (Invalid). + error: Expected a geometry type and an srid, but found (Invalid, 0). --> schema.prisma:8  |   7 |  id Int @id -  8 |  geom Geometry @db.Geometry(Invalid) +  8 |  geom Geometry @db.Geometry(Invalid, 0)  |  "#]]; diff --git a/psl/psl/tests/types/sqlite_native_types.rs b/psl/psl/tests/types/sqlite_native_types.rs index e1dc87788839..ce90f1cab4b8 100644 --- a/psl/psl/tests/types/sqlite_native_types.rs +++ b/psl/psl/tests/types/sqlite_native_types.rs @@ -45,16 +45,16 @@ fn should_fail_on_geometry_when_invalid_geometry_type() { model Blog { id Int @id - geom Geometry @db.Geometry(Invalid) + geom Geometry @db.Geometry(Invalid, 0) } "#}; let expectation = expect![[r#" - error: Expected a geometry type and an optional srid, but found (Invalid). + error: Expected a geometry type and an srid, but found (Invalid, 0). --> schema.prisma:8  |   7 |  id Int @id -  8 |  geom Geometry @db.Geometry(Invalid) +  8 |  geom Geometry @db.Geometry(Invalid, 0)  |  "#]]; From a957dcce2047888957c6ac246a3e5869e0b0fca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Wed, 9 Oct 2024 00:38:02 +0200 Subject: [PATCH 092/103] Make db geometry type params mandatory for SQLite --- .../src/builtin_connectors/sqlite_datamodel_connector.rs | 8 +++----- .../sqlite_datamodel_connector/native_types.rs | 2 +- .../src/sql_renderer/sqlite_renderer.rs | 1 - schema-engine/sql-schema-describer/src/sqlite.rs | 2 +- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs b/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs index 409c050de272..aa6568028153 100644 --- a/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs +++ b/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector.rs @@ -37,10 +37,8 @@ pub const CAPABILITIES: ConnectorCapabilities = enumflags2::make_bitflags!(Conne CreateManyWriteableAutoIncId }); -const SCALAR_TYPE_DEFAULTS: &[(ScalarType, SQLiteType)] = &[( - ScalarType::Geometry, - SQLiteType::Geometry(Some(GeometryParams::default())), -)]; +const SCALAR_TYPE_DEFAULTS: &[(ScalarType, SQLiteType)] = + &[(ScalarType::Geometry, SQLiteType::Geometry(GeometryParams::default()))]; pub struct SqliteDatamodelConnector; @@ -112,7 +110,7 @@ impl Connector for SqliteDatamodelConnector { let error = self.native_instance_error(native_type_instance); match native_type { - SQLiteType::Geometry(Some(g)) if g.srid < -1 => errors + SQLiteType::Geometry(g) if g.srid < -1 => errors .push_error(error.new_argument_m_out_of_range_error("SRID must be superior or equal to -1.", span)), _ => (), } diff --git a/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector/native_types.rs b/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector/native_types.rs index ec5aa57edbd5..5b0747cb6dfe 100644 --- a/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector/native_types.rs +++ b/psl/psl-core/src/builtin_connectors/sqlite_datamodel_connector/native_types.rs @@ -3,5 +3,5 @@ use crate::builtin_connectors::geometry::GeometryParams; crate::native_type_definition! { /// The SQLite native type enum. SQLiteType; - Geometry(Option) -> Geometry, + Geometry(GeometryParams) -> Geometry, } diff --git a/schema-engine/connectors/sql-schema-connector/src/sql_renderer/sqlite_renderer.rs b/schema-engine/connectors/sql-schema-connector/src/sql_renderer/sqlite_renderer.rs index c62bc1a9cb02..07b455b24a3e 100644 --- a/schema-engine/connectors/sql-schema-connector/src/sql_renderer/sqlite_renderer.rs +++ b/schema-engine/connectors/sql-schema-connector/src/sql_renderer/sqlite_renderer.rs @@ -165,7 +165,6 @@ impl SqlRenderer for SqliteFlavour { .fold(String::new(), |mut result, col| { let column_name = col.name(); let SQLiteType::Geometry(geom) = col.column_native_type().unwrap(); - let geom = geom.expect("Couldn't get geometry column type informations"); writeln!( result, "SELECT RecoverGeometryColumn('{table_name}', '{column_name}', {srid}, '{type_}', '{dims}');", diff --git a/schema-engine/sql-schema-describer/src/sqlite.rs b/schema-engine/sql-schema-describer/src/sqlite.rs index 2650c0bddcd4..1b47f9148761 100644 --- a/schema-engine/sql-schema-describer/src/sqlite.rs +++ b/schema-engine/sql-schema-describer/src/sqlite.rs @@ -411,7 +411,7 @@ async fn push_columns( full_data_type: column_type, family: ColumnTypeFamily::Geometry, arity, - native_type: Some(NativeTypeInstance::new(SQLiteType::Geometry(Some(params)))), + native_type: Some(NativeTypeInstance::new(SQLiteType::Geometry(params))), } } else { get_column_type(column_type, arity) From f103c02e7cff12c917c36bb1b70c495e033f1900 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Wed, 9 Oct 2024 00:56:24 +0200 Subject: [PATCH 093/103] Fix handling of raw geometry value in quaint --- quaint/src/visitor/postgres.rs | 14 +++++++------- quaint/src/visitor/sqlite.rs | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/quaint/src/visitor/postgres.rs b/quaint/src/visitor/postgres.rs index 20e9fc975771..1f66ef2d803a 100644 --- a/quaint/src/visitor/postgres.rs +++ b/quaint/src/visitor/postgres.rs @@ -45,7 +45,7 @@ impl<'a> Postgres<'a> { Ok(()) } - fn visit_geometry_from_geojson(&mut self, geometry: G, srid: Option) -> visitor::Result + fn visit_geometry_from_geojson(&mut self, geometry: G, srid: S) -> visitor::Result where G: Into>, S: Into>, @@ -59,12 +59,12 @@ impl<'a> Postgres<'a> { s.visit_expression(geometry.into()) })?; s.write(",")?; - s.visit_expression(srid.map(Into::into).unwrap_or(4326.into()))?; + s.visit_expression(srid.into())?; Ok(()) }) } - fn visit_geography_from_geojson(&mut self, geometry: G, srid: Option) -> visitor::Result + fn visit_geography_from_geojson(&mut self, geometry: G, srid: S) -> visitor::Result where G: Into>, S: Into>, @@ -290,12 +290,12 @@ impl<'a> Visitor<'a> for Postgres<'a> { ValueType::Date(date) => date.map(|date| self.write(format!("'{date}'"))), ValueType::Time(time) => time.map(|time| self.write(format!("'{time}'"))), ValueType::Geometry(geometry) => geometry.as_ref().map(|geometry| { - let srid = get_geometry_srid(geometry); - self.visit_geometry_from_geojson(geometry.to_string().raw(), srid.map(IntoRaw::raw)) + let srid = get_geometry_srid(geometry).unwrap_or(4326); + self.visit_geometry_from_geojson(geometry.to_string().raw(), srid.raw()) }), ValueType::Geography(geometry) => geometry.as_ref().map(|geometry| { - let srid = get_geometry_srid(geometry); - self.visit_geography_from_geojson(geometry.to_string().raw(), srid.map(IntoRaw::raw)) + let srid = get_geometry_srid(geometry).unwrap_or(4326); + self.visit_geography_from_geojson(geometry.to_string().raw(), srid.raw()) }), }; diff --git a/quaint/src/visitor/sqlite.rs b/quaint/src/visitor/sqlite.rs index f42bd6a6dea6..dbb06f71c4f2 100644 --- a/quaint/src/visitor/sqlite.rs +++ b/quaint/src/visitor/sqlite.rs @@ -35,7 +35,7 @@ impl<'a> Sqlite<'a> { Ok(()) } - fn visit_geometry_from_geojson(&mut self, geometry: G, srid: Option) -> visitor::Result + fn visit_geometry_from_geojson(&mut self, geometry: G, srid: S) -> visitor::Result where G: Into>, S: Into>, @@ -46,7 +46,7 @@ impl<'a> Sqlite<'a> { self.surround_with("SetSRID(", ")", |s| { s.surround_with("GeomFromGeoJSON(", ")", |ref mut s| s.visit_expression(geometry.into()))?; s.write(",")?; - s.visit_expression(srid.map(Into::into).unwrap_or(4326.into()))?; + s.visit_expression(srid.into())?; Ok(()) }) } @@ -155,12 +155,12 @@ impl<'a> Visitor<'a> for Sqlite<'a> { ValueType::Time(time) => time.map(|time| self.write(format!("'{time}'"))), ValueType::Xml(cow) => cow.as_ref().map(|cow| self.write(format!("'{cow}'"))), ValueType::Geometry(geometry) => geometry.as_ref().map(|geometry| { - let srid = get_geometry_srid(geometry); - self.visit_geometry_from_geojson(geometry.to_string().raw(), srid.map(IntoRaw::raw)) + let srid = get_geometry_srid(geometry).unwrap_or(4326); + self.visit_geometry_from_geojson(geometry.to_string().raw(), srid.raw()) }), ValueType::Geography(geometry) => geometry.as_ref().map(|geometry| { - let srid = get_geometry_srid(geometry); - self.visit_geometry_from_geojson(geometry.to_string().raw(), srid.map(IntoRaw::raw)) + let srid = get_geometry_srid(geometry).unwrap_or(4326); + self.visit_geometry_from_geojson(geometry.to_string().raw(), srid.raw()) }), }; From 477bae553a2e598150d3e2852f8961e65b185354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Wed, 9 Oct 2024 00:59:40 +0200 Subject: [PATCH 094/103] Revert changes to CI runners --- .github/workflows/test-query-engine-template.yml | 4 +++- .github/workflows/test-query-engine.yml | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-query-engine-template.yml b/.github/workflows/test-query-engine-template.yml index 87a5ff543923..fe9b42e6fd5c 100644 --- a/.github/workflows/test-query-engine-template.yml +++ b/.github/workflows/test-query-engine-template.yml @@ -49,7 +49,9 @@ jobs: PRISMA_ENGINE_PROTOCOL: ${{ matrix.engine_protocol }} PRISMA_RELATION_LOAD_STRATEGY: ${{ matrix.relation_load_strategy }} - runs-on: "ubuntu-${{ inputs.ubuntu }}" + runs-on: "ubuntu-20.04" + # TODO: Replace with the following once `prisma@5.20.0` is released. + # runs-on: "ubuntu-${{ inputs.ubuntu }}" steps: - uses: actions/checkout@v4 - uses: actions-rust-lang/setup-rust-toolchain@v1 diff --git a/.github/workflows/test-query-engine.yml b/.github/workflows/test-query-engine.yml index 66c4095a4a7d..838fb435616c 100644 --- a/.github/workflows/test-query-engine.yml +++ b/.github/workflows/test-query-engine.yml @@ -127,6 +127,7 @@ jobs: version: "2019" - name: "mssql_2017" version: "2017" + ubuntu: "20.04" uses: ./.github/workflows/test-query-engine-template.yml name: mssql ${{ matrix.database.version }} with: @@ -143,8 +144,8 @@ jobs: database: - name: "sqlite" version: "3" - - name: "spatialite" - version: "3-spatialite" + # - name: "spatialite" + # version: "3-spatialite" uses: ./.github/workflows/test-query-engine-template.yml name: sqlite ${{ matrix.database.version }} with: From 2ddce28f1741147e954e64cabd2b9bd74f64fa5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Wed, 9 Oct 2024 01:07:11 +0200 Subject: [PATCH 095/103] Fix cockroachdb test --- schema-engine/sql-introspection-tests/tests/cockroachdb/gin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schema-engine/sql-introspection-tests/tests/cockroachdb/gin.rs b/schema-engine/sql-introspection-tests/tests/cockroachdb/gin.rs index cb2a52f91890..9eaad8b77277 100644 --- a/schema-engine/sql-introspection-tests/tests/cockroachdb/gin.rs +++ b/schema-engine/sql-introspection-tests/tests/cockroachdb/gin.rs @@ -22,7 +22,7 @@ async fn gin_unsupported_type(api: &mut TestApi) -> TestResult { let expected = expect![[r#" model A { id BigInt @id @default(autoincrement()) - data Geometry + data Geometry @db.Geometry(Geometry, 0) @@index([data], type: Gin) } From 943c80da8896e8138c30ce0e7a164cc81580dabe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Wed, 9 Oct 2024 10:36:19 +0200 Subject: [PATCH 096/103] Fix postgres tests --- quaint/src/visitor/postgres.rs | 2 +- quaint/src/visitor/sqlite.rs | 2 +- .../data_types/native_types/postgres.rs | 32 +++++++++---------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/quaint/src/visitor/postgres.rs b/quaint/src/visitor/postgres.rs index 1f66ef2d803a..937ad2e6ed88 100644 --- a/quaint/src/visitor/postgres.rs +++ b/quaint/src/visitor/postgres.rs @@ -830,7 +830,7 @@ impl<'a> Visitor<'a> for Postgres<'a> { } fn visit_parameterized_geometry(&mut self, geometry: geojson::Geometry) -> visitor::Result { - let srid = get_geometry_srid(&geometry); + let srid = get_geometry_srid(&geometry).unwrap_or(4326); self.visit_geometry_from_geojson(geometry.to_string(), srid)?; Ok(()) diff --git a/quaint/src/visitor/sqlite.rs b/quaint/src/visitor/sqlite.rs index dbb06f71c4f2..441d9c3e1e67 100644 --- a/quaint/src/visitor/sqlite.rs +++ b/quaint/src/visitor/sqlite.rs @@ -520,7 +520,7 @@ impl<'a> Visitor<'a> for Sqlite<'a> { } fn visit_parameterized_geometry(&mut self, geometry: geojson::Geometry) -> visitor::Result { - let srid = get_geometry_srid(&geometry); + let srid = get_geometry_srid(&geometry).unwrap_or(4326); self.visit_geometry_from_geojson(geometry.to_string(), srid) } diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/postgres.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/postgres.rs index 4d42508bfb68..b67e98bb025f 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/postgres.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/writes/data_types/native_types/postgres.rs @@ -352,14 +352,14 @@ mod postgres { r#"model Model { @@schema("test") #id(id, String, @id, @default(cuid())) - geometry Geometry @test.Geometry(Geometry) - geometry_point Geometry @test.Geometry(Point) - geometry_line Geometry @test.Geometry(LineString) - geometry_poly Geometry @test.Geometry(Polygon) - geometry_multipoint Geometry @test.Geometry(MultiPoint) - geometry_multiline Geometry @test.Geometry(MultiLineString) - geometry_multipoly Geometry @test.Geometry(MultiPolygon) - geometry_collection Geometry @test.Geometry(GeometryCollection) + geometry Geometry @test.Geometry(Geometry, 4326) + geometry_point Geometry @test.Geometry(Point, 4326) + geometry_line Geometry @test.Geometry(LineString, 4326) + geometry_poly Geometry @test.Geometry(Polygon, 4326) + geometry_multipoint Geometry @test.Geometry(MultiPoint, 4326) + geometry_multiline Geometry @test.Geometry(MultiLineString, 4326) + geometry_multipoly Geometry @test.Geometry(MultiPolygon, 4326) + geometry_collection Geometry @test.Geometry(GeometryCollection, 4326) }"# }; @@ -465,14 +465,14 @@ mod postgres { r#"model Model { @@schema("test") #id(id, String, @id, @default(cuid())) - geography Geometry @test.Geography(Geometry) - geography_point Geometry @test.Geography(Point) - geography_line Geometry @test.Geography(LineString) - geography_poly Geometry @test.Geography(Polygon) - geography_multipoint Geometry @test.Geography(MultiPoint) - geography_multiline Geometry @test.Geography(MultiLineString) - geography_multipoly Geometry @test.Geography(MultiPolygon) - geography_collection Geometry @test.Geography(GeometryCollection) + geography Geometry @test.Geography(Geometry, 4326) + geography_point Geometry @test.Geography(Point, 4326) + geography_line Geometry @test.Geography(LineString, 4326) + geography_poly Geometry @test.Geography(Polygon, 4326) + geography_multipoint Geometry @test.Geography(MultiPoint, 4326) + geography_multiline Geometry @test.Geography(MultiLineString, 4326) + geography_multipoly Geometry @test.Geography(MultiPolygon, 4326) + geography_collection Geometry @test.Geography(GeometryCollection, 4326) }"# }; From 742732932d50041a2e5a68c0f0b509d2fd66de0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Wed, 9 Oct 2024 18:48:38 +0200 Subject: [PATCH 097/103] Remove PrismaValue::GeoJson --- libs/prisma-value/src/lib.rs | 2 -- .../mongodb-query-connector/src/value.rs | 17 ++--------------- .../src/model_extensions/scalar_field.rs | 7 ++----- .../connectors/sql-query-connector/src/row.rs | 6 +++--- .../connectors/sql-query-connector/src/value.rs | 6 +++--- query-engine/core/src/query_document/parser.rs | 5 ++--- query-engine/core/src/response_ir/internal.rs | 5 +---- .../src/ast_builders/datamodel_ast_builder.rs | 1 - .../query-structure/src/prisma_value_ext.rs | 2 +- 9 files changed, 14 insertions(+), 37 deletions(-) diff --git a/libs/prisma-value/src/lib.rs b/libs/prisma-value/src/lib.rs index f25954b29572..1aff2618f597 100644 --- a/libs/prisma-value/src/lib.rs +++ b/libs/prisma-value/src/lib.rs @@ -28,7 +28,6 @@ pub enum PrismaValue { Uuid(Uuid), List(PrismaListValue), Json(String), - GeoJson(String), /// A collections of key-value pairs constituting an object. #[serde(serialize_with = "serialize_object")] @@ -331,7 +330,6 @@ impl fmt::Display for PrismaValue { PrismaValue::Null => "null".fmt(f), PrismaValue::Uuid(x) => x.fmt(f), PrismaValue::Json(x) => x.fmt(f), - PrismaValue::GeoJson(x) => x.fmt(f), PrismaValue::BigInt(x) => x.fmt(f), PrismaValue::List(x) => { let as_string = format!("{x:?}"); diff --git a/query-engine/connectors/mongodb-query-connector/src/value.rs b/query-engine/connectors/mongodb-query-connector/src/value.rs index eda8122e611d..c9dccd23cc4b 100644 --- a/query-engine/connectors/mongodb-query-connector/src/value.rs +++ b/query-engine/connectors/mongodb-query-connector/src/value.rs @@ -198,17 +198,6 @@ impl IntoBson for (&MongoDbType, PrismaValue) { })? } - // Geometry - (MongoDbType::Json, PrismaValue::GeoJson(json)) => { - let geometry = geojson::Geometry::from_str(&json)?; - let val: Value = geojson::GeoJson::Geometry(geometry).into(); - - Bson::try_from(val).map_err(|_| MongoError::ConversionError { - from: "Stringified GeoJSON".to_owned(), - to: "Mongo BSON (extJSON)".to_owned(), - })? - } - // Unhandled conversions (mdb_type, p_val) => { return Err(MongoError::ConversionError { @@ -278,7 +267,7 @@ impl IntoBson for (&TypeIdentifier, PrismaValue) { } // Geometry - (TypeIdentifier::Geometry, PrismaValue::GeoJson(json)) => { + (TypeIdentifier::Geometry, PrismaValue::Json(json)) => { let geometry = geojson::Geometry::from_str(&json)?; let val: Value = geojson::GeoJson::Geometry(geometry).into(); Bson::try_from(val).map_err(|_| MongoError::ConversionError { @@ -399,9 +388,7 @@ fn read_scalar_value(bson: Bson, meta: &ScalarOutputMeta) -> crate::Result PrismaValue::Json(serde_json::to_string(&bson.into_relaxed_extjson())?), // Geometry - (TypeIdentifier::Geometry, bson @ Bson::Document(_)) => { - PrismaValue::GeoJson(serde_json::to_string(&bson.into_relaxed_extjson())?) - } + (TypeIdentifier::Geometry, bson) => PrismaValue::Json(serde_json::to_string(&bson.into_relaxed_extjson())?), (ident, bson) => { return Err(MongoError::ConversionError { diff --git a/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs b/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs index d5bc9b5010e0..0e917c2378e0 100644 --- a/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs +++ b/query-engine/connectors/sql-query-connector/src/model_extensions/scalar_field.rs @@ -51,10 +51,9 @@ impl ScalarFieldExt for ScalarField { (PrismaValue::BigInt(i), _) => i.into(), (PrismaValue::Uuid(u), _) => u.to_string().into(), (PrismaValue::List(l), _) => Value::array(l.into_iter().map(|x| self.value(x, ctx))), - (PrismaValue::Json(s), _) => Value::json(serde_json::from_str::(&s).unwrap()), (PrismaValue::Bytes(b), _) => Value::bytes(b), (PrismaValue::Object(_), _) => unimplemented!(), - (PrismaValue::GeoJson(s), _) => { + (PrismaValue::Json(s), TypeIdentifier::Geometry) => { let geometry = s.parse::().unwrap(); match self.type_family() { TypeFamily::Geography => Value::geography(geometry), @@ -62,6 +61,7 @@ impl ScalarFieldExt for ScalarField { _ => unreachable!(), } } + (PrismaValue::Json(s), _) => Value::json(serde_json::from_str::(&s).unwrap()), (PrismaValue::Null, ident) => match ident { TypeIdentifier::String => Value::null_text(), TypeIdentifier::Float => Value::null_numeric(), @@ -141,9 +141,6 @@ pub fn convert_lossy<'a>(pv: PrismaValue) -> Value<'a> { PrismaValue::List(l) => Value::array(l.into_iter().map(convert_lossy)), PrismaValue::Json(s) => Value::json(serde_json::from_str(&s).unwrap()), PrismaValue::Bytes(b) => Value::bytes(b), - // TODO@geom: Fix this when we know how to cast GeoJSON to an appropriate DB value - PrismaValue::GeoJson(s) => Value::json(serde_json::from_str(&s).unwrap()), - // PrismaValue::Geometry(s) => Value::geometry(GeometryValue::from_str(&s).unwrap()), PrismaValue::Null => Value::null_int32(), // Can't tell which type the null is supposed to be. PrismaValue::Object(_) => unimplemented!(), } diff --git a/query-engine/connectors/sql-query-connector/src/row.rs b/query-engine/connectors/sql-query-connector/src/row.rs index 08ea41c174fe..a8f3c3992026 100644 --- a/query-engine/connectors/sql-query-connector/src/row.rs +++ b/query-engine/connectors/sql-query-connector/src/row.rs @@ -293,12 +293,12 @@ fn row_value_to_prisma_value(p_value: Value, meta: ColumnMetadata<'_>) -> Result value if value.is_null() => PrismaValue::Null, ValueType::Json(Some(mut geojson)) => { geojson.as_object_mut().map(trim_redundent_crs); - PrismaValue::GeoJson(geojson.to_string()) + PrismaValue::Json(geojson.to_string()) } ValueType::Text(Some(ref geom)) if geom.starts_with("{") => { let mut geojson = geom.parse::()?; geojson.as_object_mut().map(trim_redundent_crs); - PrismaValue::GeoJson(geojson.to_string()) + PrismaValue::Json(geojson.to_string()) } ValueType::Text(Some(ref geom)) => { // SQlite and Postgres return GeoJSON as strings. SQL Server cannot return geometry as GeoJSON, @@ -313,7 +313,7 @@ fn row_value_to_prisma_value(p_value: Value, meta: ColumnMetadata<'_>) -> Result let crs = json!({"type": "name", "properties": {"name": format!("EPSG:{srid}")}}); geojson.as_object_mut().map(|g| g.insert("crs".to_string(), crs)); } - PrismaValue::GeoJson(geojson.to_string()) + PrismaValue::Json(geojson.to_string()) } _ => return Err(create_error(&p_value)), }, diff --git a/query-engine/connectors/sql-query-connector/src/value.rs b/query-engine/connectors/sql-query-connector/src/value.rs index f1e7c63e1e72..d23c50896ca6 100644 --- a/query-engine/connectors/sql-query-connector/src/value.rs +++ b/query-engine/connectors/sql-query-connector/src/value.rs @@ -99,9 +99,9 @@ pub fn to_prisma_value<'a, T: Into>>(qv: T) -> crate::Result s - .map(|s| PrismaValue::GeoJson(s.to_string())) - .unwrap_or(PrismaValue::Null), + ValueType::Geometry(s) | ValueType::Geography(s) => { + s.map(|s| PrismaValue::Json(s.to_string())).unwrap_or(PrismaValue::Null) + } }; Ok(val) diff --git a/query-engine/core/src/query_document/parser.rs b/query-engine/core/src/query_document/parser.rs index 88be0f9b0e64..ec96e2e527a8 100644 --- a/query-engine/core/src/query_document/parser.rs +++ b/query-engine/core/src/query_document/parser.rs @@ -372,7 +372,7 @@ impl QueryDocumentParser { (PrismaValue::Bytes(bytes), ScalarType::Bytes) => Ok(PrismaValue::Bytes(bytes)), (PrismaValue::BigInt(b_int), ScalarType::BigInt) => Ok(PrismaValue::BigInt(b_int)), (PrismaValue::DateTime(s), ScalarType::DateTime) => Ok(PrismaValue::DateTime(s)), - (PrismaValue::GeoJson(s), ScalarType::Geometry) => Ok(PrismaValue::GeoJson(s)), + (PrismaValue::Json(s), ScalarType::Geometry) => Ok(PrismaValue::Json(s)), (PrismaValue::Null, ScalarType::Null) => Ok(PrismaValue::Null), // String coercion matchers @@ -388,7 +388,7 @@ impl QueryDocumentParser { (PrismaValue::String(s), ScalarType::Json) => Ok(PrismaValue::Json( self.parse_json(selection_path, argument_path, &s).map(|_| s)?, )), - (PrismaValue::Json(s) | PrismaValue::String(s), ScalarType::Geometry) => Ok(PrismaValue::GeoJson( + (PrismaValue::String(s), ScalarType::Geometry) => Ok(PrismaValue::Json( self.parse_geojson(selection_path, argument_path, &s).map(|_| s)?, )), (PrismaValue::String(s), ScalarType::DateTime) => self @@ -919,7 +919,6 @@ pub(crate) mod conversions { format!("({})", itertools::join(v.iter().map(prisma_value_to_type_name), ", ")) } PrismaValue::Json(_) => "JSON".to_string(), - PrismaValue::GeoJson(_) => "GeoJSON".to_string(), PrismaValue::Object(_) => "Object".to_string(), PrismaValue::Null => "Null".to_string(), PrismaValue::DateTime(_) => "DateTime".to_string(), diff --git a/query-engine/core/src/response_ir/internal.rs b/query-engine/core/src/response_ir/internal.rs index 5168f9deb782..ea93c5a81cb3 100644 --- a/query-engine/core/src/response_ir/internal.rs +++ b/query-engine/core/src/response_ir/internal.rs @@ -810,7 +810,7 @@ fn convert_prisma_value_graphql_protocol( (ScalarType::DateTime, PrismaValue::DateTime(dt)) => PrismaValue::DateTime(dt), (ScalarType::UUID, PrismaValue::Uuid(u)) => PrismaValue::Uuid(u), (ScalarType::Bytes, PrismaValue::Bytes(b)) => PrismaValue::Bytes(b), - (ScalarType::Geometry, PrismaValue::GeoJson(s)) => PrismaValue::GeoJson(s), + (ScalarType::Geometry, PrismaValue::Json(s)) => PrismaValue::Json(s), // The Decimal type doesn't have a corresponding PrismaValue variant. We need to serialize it // to String so that client can deserialize it as Decimal again. @@ -854,9 +854,6 @@ fn convert_prisma_value_json_protocol( (ScalarType::Bytes, PrismaValue::Bytes(x)) => { custom_types::make_object(custom_types::BYTES, PrismaValue::Bytes(x)) } - (ScalarType::Geometry, PrismaValue::GeoJson(x)) => { - custom_types::make_object(custom_types::JSON, PrismaValue::GeoJson(x)) - } // Identity matchers (ScalarType::String, PrismaValue::String(x)) => PrismaValue::String(x), diff --git a/query-engine/dmmf/src/ast_builders/datamodel_ast_builder.rs b/query-engine/dmmf/src/ast_builders/datamodel_ast_builder.rs index 21977414db73..a0e120216073 100644 --- a/query-engine/dmmf/src/ast_builders/datamodel_ast_builder.rs +++ b/query-engine/dmmf/src/ast_builders/datamodel_ast_builder.rs @@ -316,7 +316,6 @@ fn prisma_value_to_serde(value: &PrismaValue) -> serde_json::Value { PrismaValue::Null => serde_json::Value::Null, PrismaValue::Uuid(val) => serde_json::Value::String(val.to_string()), PrismaValue::Json(val) => serde_json::Value::String(val.to_string()), - PrismaValue::GeoJson(val) => serde_json::Value::String(val.to_string()), PrismaValue::List(value_vec) => serde_json::Value::Array(value_vec.iter().map(prisma_value_to_serde).collect()), PrismaValue::Bytes(b) => serde_json::Value::String(encode_bytes(b)), PrismaValue::Object(pairs) => { diff --git a/query-engine/query-structure/src/prisma_value_ext.rs b/query-engine/query-structure/src/prisma_value_ext.rs index e4278b6c348a..ab6257209d31 100644 --- a/query-engine/query-structure/src/prisma_value_ext.rs +++ b/query-engine/query-structure/src/prisma_value_ext.rs @@ -23,7 +23,7 @@ impl PrismaValueExtensions for PrismaValue { (val @ PrismaValue::BigInt(_), TypeIdentifier::BigInt) => val, (val @ PrismaValue::Bytes(_), TypeIdentifier::Bytes) => val, (val @ PrismaValue::Json(_), TypeIdentifier::Json) => val, - (val @ PrismaValue::GeoJson(_), TypeIdentifier::Geometry) => val, + (val @ PrismaValue::Json(_), TypeIdentifier::Geometry) => val, // Valid String coercions (PrismaValue::Int(i), TypeIdentifier::String) => PrismaValue::String(format!("{i}")), From c7d650d0ea79930e177c2a4aaef952adbc784f5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Thu, 10 Oct 2024 14:15:28 +0200 Subject: [PATCH 098/103] Rename input/output type functions geojson to geometry --- query-engine/schema/src/build/input_types/mod.rs | 2 +- query-engine/schema/src/build/output_types/field.rs | 2 +- query-engine/schema/src/input_types.rs | 2 +- query-engine/schema/src/output_types.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/query-engine/schema/src/build/input_types/mod.rs b/query-engine/schema/src/build/input_types/mod.rs index 6b4684d66014..538ab26cf775 100644 --- a/query-engine/schema/src/build/input_types/mod.rs +++ b/query-engine/schema/src/build/input_types/mod.rs @@ -19,7 +19,7 @@ fn map_scalar_input_type(ctx: &'_ QuerySchema, typ: TypeIdentifier, list: bool) TypeIdentifier::UUID => InputType::uuid(), TypeIdentifier::DateTime => InputType::date_time(), TypeIdentifier::Json => InputType::json(), - TypeIdentifier::Geometry => InputType::geojson(), + TypeIdentifier::Geometry => InputType::geometry(), TypeIdentifier::Enum(id) => InputType::enum_type(map_schema_enum_type(ctx, id)), TypeIdentifier::Bytes => InputType::bytes(), TypeIdentifier::BigInt => InputType::bigint(), diff --git a/query-engine/schema/src/build/output_types/field.rs b/query-engine/schema/src/build/output_types/field.rs index 411e72896b60..5017a9b850a6 100644 --- a/query-engine/schema/src/build/output_types/field.rs +++ b/query-engine/schema/src/build/output_types/field.rs @@ -34,7 +34,7 @@ pub(crate) fn map_scalar_output_type<'a>(ctx: &'a QuerySchema, typ: &TypeIdentif TypeIdentifier::Boolean => OutputType::boolean(), TypeIdentifier::Enum(e) => OutputType::enum_type(map_schema_enum_type(ctx, *e)), TypeIdentifier::Json => OutputType::json(), - TypeIdentifier::Geometry => OutputType::geojson(), + TypeIdentifier::Geometry => OutputType::geometry(), TypeIdentifier::DateTime => OutputType::date_time(), TypeIdentifier::UUID => OutputType::uuid(), TypeIdentifier::Int => OutputType::int(), diff --git a/query-engine/schema/src/input_types.rs b/query-engine/schema/src/input_types.rs index 7bbd48e1b18f..147e20e6a186 100644 --- a/query-engine/schema/src/input_types.rs +++ b/query-engine/schema/src/input_types.rs @@ -271,7 +271,7 @@ impl<'a> InputType<'a> { InputType::Scalar(ScalarType::Bytes) } - pub(crate) fn geojson() -> InputType<'a> { + pub(crate) fn geometry() -> InputType<'a> { InputType::Scalar(ScalarType::Geometry) } diff --git a/query-engine/schema/src/output_types.rs b/query-engine/schema/src/output_types.rs index 91589c986653..e67e1e7e8e61 100644 --- a/query-engine/schema/src/output_types.rs +++ b/query-engine/schema/src/output_types.rs @@ -77,7 +77,7 @@ impl<'a> OutputType<'a> { InnerOutputType::Scalar(ScalarType::Bytes) } - pub(crate) fn geojson() -> InnerOutputType<'a> { + pub(crate) fn geometry() -> InnerOutputType<'a> { InnerOutputType::Scalar(ScalarType::Geometry) } From 9f0203c2868b81744c1aaa375b007761d26d6ba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Thu, 10 Oct 2024 14:17:00 +0200 Subject: [PATCH 099/103] Fix geometry / json value / prisma value conversions --- .../src/database/operations/read/coerce.rs | 4 ++-- query-engine/core/src/response_ir/internal.rs | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/query-engine/connectors/sql-query-connector/src/database/operations/read/coerce.rs b/query-engine/connectors/sql-query-connector/src/database/operations/read/coerce.rs index d570eab105a7..2826ef6f0536 100644 --- a/query-engine/connectors/sql-query-connector/src/database/operations/read/coerce.rs +++ b/query-engine/connectors/sql-query-connector/src/database/operations/read/coerce.rs @@ -121,11 +121,11 @@ fn coerce_json_relation_to_pv(value: serde_json::Value, rs: &RelationSelection) } pub(crate) fn coerce_json_scalar_to_pv(value: serde_json::Value, sf: &ScalarField) -> crate::Result { - if sf.type_identifier().is_json() && !sf.is_list() { + if (sf.type_identifier().is_json() || sf.type_identifier().is_geometry()) && !sf.is_list() { return Ok(PrismaValue::Json(serde_json::to_string(&value)?)); } - if sf.type_identifier().is_json() && sf.is_list() { + if (sf.type_identifier().is_json() || sf.type_identifier().is_geometry()) && sf.is_list() { return match value { serde_json::Value::Null => Ok(PrismaValue::List(vec![])), serde_json::Value::Array(values) => Ok(PrismaValue::List( diff --git a/query-engine/core/src/response_ir/internal.rs b/query-engine/core/src/response_ir/internal.rs index ea93c5a81cb3..f794cba38cce 100644 --- a/query-engine/core/src/response_ir/internal.rs +++ b/query-engine/core/src/response_ir/internal.rs @@ -854,6 +854,9 @@ fn convert_prisma_value_json_protocol( (ScalarType::Bytes, PrismaValue::Bytes(x)) => { custom_types::make_object(custom_types::BYTES, PrismaValue::Bytes(x)) } + (ScalarType::Geometry, PrismaValue::Json(x)) => { + custom_types::make_object(custom_types::JSON, PrismaValue::Json(x)) + } // Identity matchers (ScalarType::String, PrismaValue::String(x)) => PrismaValue::String(x), From ca2e009d2bc04582510fea31eb6c85c900180599 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 14 Oct 2024 11:45:43 +0200 Subject: [PATCH 100/103] Add JSON protocol geometry input test --- .../query-engine-tests/src/schemas/geom.rs | 13 ++++++++ .../query-engine-tests/src/schemas/mod.rs | 2 ++ .../tests/queries/data_types/geometry.rs | 32 +++++++++++++++++++ .../tests/queries/data_types/mod.rs | 1 + .../core/src/query_document/parser.rs | 2 +- 5 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 query-engine/connector-test-kit-rs/query-engine-tests/src/schemas/geom.rs create mode 100644 query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/data_types/geometry.rs diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/src/schemas/geom.rs b/query-engine/connector-test-kit-rs/query-engine-tests/src/schemas/geom.rs new file mode 100644 index 000000000000..76ccbe600863 --- /dev/null +++ b/query-engine/connector-test-kit-rs/query-engine-tests/src/schemas/geom.rs @@ -0,0 +1,13 @@ +use indoc::indoc; + +/// Basic Test model containing a single geometry field. +pub fn geom() -> String { + let schema = indoc! { + "model TestModel { + #id(id, Int, @id) + geom Geometry + }" + }; + + schema.to_owned() +} diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/src/schemas/mod.rs b/query-engine/connector-test-kit-rs/query-engine-tests/src/schemas/mod.rs index cd9d2d9d1cb2..a7f6a71828ce 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/src/schemas/mod.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/src/schemas/mod.rs @@ -1,11 +1,13 @@ mod basic; mod composites; +mod geom; mod json; mod many_to_many; mod one_to_many; pub use basic::*; pub use composites::*; +pub use geom::*; pub use json::*; pub use many_to_many::*; pub use one_to_many::*; diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/data_types/geometry.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/data_types/geometry.rs new file mode 100644 index 000000000000..28f2d8c2885d --- /dev/null +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/data_types/geometry.rs @@ -0,0 +1,32 @@ +use query_engine_tests::*; + +#[test_suite(schema(geom))] +mod json { + + #[connector_test] + async fn geometry_json_protocol(runner: Runner) -> TestResult<()> { + let res = runner + .query_json( + r#"{ + "modelName": "TestModel", + "action": "createOne", + "query": { + "selection": { "geom": true }, + "arguments": { + "data": { + "id": 1, + "geom": { "$type": "Raw", "value": {"type": "Point", "coordinates": [0, 0] } } + } + } + } + }"#, + ) + .await?; + + res.assert_success(); + + insta::assert_snapshot!(res.to_string(), @r###"{"data":{"createOneTestModel":{"geom":{"$type":"Json","value":"{\"type\":\"Point\",\"coordinates\":[0,0]}"}}}}"###); + + Ok(()) + } +} diff --git a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/data_types/mod.rs b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/data_types/mod.rs index 127e5e23c29a..acd50a8c8c92 100644 --- a/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/data_types/mod.rs +++ b/query-engine/connector-test-kit-rs/query-engine-tests/tests/queries/data_types/mod.rs @@ -5,6 +5,7 @@ mod datetime; mod decimal; mod enum_type; mod float; +mod geometry; mod int; mod json; mod native; diff --git a/query-engine/core/src/query_document/parser.rs b/query-engine/core/src/query_document/parser.rs index ec96e2e527a8..7cba0e0f51c9 100644 --- a/query-engine/core/src/query_document/parser.rs +++ b/query-engine/core/src/query_document/parser.rs @@ -253,7 +253,7 @@ impl QueryDocumentParser { // This is an early catch-all. // We do not get into this catch-all _if_ the value is already Json, if it's a FieldRef or if it's an Enum. // We don't because they've already been desambiguified at the procotol adapter level. - (value, InputType::<'a>::Scalar(ScalarType::Json)) + (value, InputType::<'a>::Scalar(ScalarType::Json | ScalarType::Geometry)) if value.should_be_parsed_as_json() && get_engine_protocol().is_json() => { return Ok(ParsedInputValue::Single(self.to_json( From bdcc984f2c785001ddf7bb73f05da42745403a43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 14 Oct 2024 11:45:54 +0200 Subject: [PATCH 101/103] Add TODOs --- .../core/src/query_graph_builder/extractors/filters/scalar.rs | 1 + query-engine/query-structure/src/field/scalar.rs | 1 + .../schema/src/build/input_types/fields/field_filter_types.rs | 1 + 3 files changed, 3 insertions(+) diff --git a/query-engine/core/src/query_graph_builder/extractors/filters/scalar.rs b/query-engine/core/src/query_graph_builder/extractors/filters/scalar.rs index 47b382ae2bf5..0c9055f1227d 100644 --- a/query-engine/core/src/query_graph_builder/extractors/filters/scalar.rs +++ b/query-engine/core/src/query_graph_builder/extractors/filters/scalar.rs @@ -50,6 +50,7 @@ impl<'a> ScalarFilterParser<'a> { let filters: Vec = filter_map .into_iter() .map(|(name, value)| match self.field().type_identifier() { + // TODO@geometry: should we add TypeIdentifier::Geometry here ? TypeIdentifier::Json => self.parse_json(&name, value, json_path.clone()), _ => self.parse_scalar(&name, value), }) diff --git a/query-engine/query-structure/src/field/scalar.rs b/query-engine/query-structure/src/field/scalar.rs index 119511d10fed..7adef45adfae 100644 --- a/query-engine/query-structure/src/field/scalar.rs +++ b/query-engine/query-structure/src/field/scalar.rs @@ -290,6 +290,7 @@ pub fn dml_default_kind(default_value: &ast::Expression, scalar_type: Option DefaultKind::Single(PrismaValue::Json(v.parse().unwrap())), Some(ScalarType::Decimal) => DefaultKind::Single(PrismaValue::Float(v.parse().unwrap())), Some(ScalarType::Bytes) => DefaultKind::Single(PrismaValue::Bytes(prisma_value::decode_bytes(v).unwrap())), + // TODO@geometry: Add geometry case here ? other => unreachable!("{:?}", other), }, ast::Expression::Array(values, _) => { diff --git a/query-engine/schema/src/build/input_types/fields/field_filter_types.rs b/query-engine/schema/src/build/input_types/fields/field_filter_types.rs index 154401d9b850..9a2beaf6ca82 100644 --- a/query-engine/schema/src/build/input_types/fields/field_filter_types.rs +++ b/query-engine/schema/src/build/input_types/fields/field_filter_types.rs @@ -44,6 +44,7 @@ pub(crate) fn get_field_filter_types( include_aggregates, ))]; + // TODO@geometry: Add TypeIdentifier::Geometry case here ? if sf.type_identifier() != TypeIdentifier::Json { types.push(map_scalar_input_type_for_field(ctx, &sf)); // Scalar equality shorthand } From 989b8764a22d3a3fb3f3c5c8f8fa62b8218ff0fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 14 Oct 2024 15:59:12 +0200 Subject: [PATCH 102/103] Validate geometries on JSON protocol --- .../core/src/query_document/parser.rs | 42 ++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/query-engine/core/src/query_document/parser.rs b/query-engine/core/src/query_document/parser.rs index 7cba0e0f51c9..a4e49d817782 100644 --- a/query-engine/core/src/query_document/parser.rs +++ b/query-engine/core/src/query_document/parser.rs @@ -253,7 +253,7 @@ impl QueryDocumentParser { // This is an early catch-all. // We do not get into this catch-all _if_ the value is already Json, if it's a FieldRef or if it's an Enum. // We don't because they've already been desambiguified at the procotol adapter level. - (value, InputType::<'a>::Scalar(ScalarType::Json | ScalarType::Geometry)) + (value, InputType::<'a>::Scalar(ScalarType::Json)) if value.should_be_parsed_as_json() && get_engine_protocol().is_json() => { return Ok(ParsedInputValue::Single(self.to_json( @@ -262,6 +262,15 @@ impl QueryDocumentParser { &value, )?)) } + (value, InputType::<'a>::Scalar(ScalarType::Geometry)) + if value.should_be_parsed_as_json() && get_engine_protocol().is_json() => + { + return Ok(ParsedInputValue::Single(self.to_geojson( + &selection_path, + &argument_path, + &value, + )?)) + } // With the JSON protocol, JSON values are sent as deserialized values. // This means that a JsonList([1, 2]) will be coerced as an `ArgumentValue::List([1, 2])`. // We need this early matcher to make sure we coerce this array back to JSON. @@ -372,9 +381,13 @@ impl QueryDocumentParser { (PrismaValue::Bytes(bytes), ScalarType::Bytes) => Ok(PrismaValue::Bytes(bytes)), (PrismaValue::BigInt(b_int), ScalarType::BigInt) => Ok(PrismaValue::BigInt(b_int)), (PrismaValue::DateTime(s), ScalarType::DateTime) => Ok(PrismaValue::DateTime(s)), - (PrismaValue::Json(s), ScalarType::Geometry) => Ok(PrismaValue::Json(s)), (PrismaValue::Null, ScalarType::Null) => Ok(PrismaValue::Null), + // Geometry validation + (PrismaValue::Json(s) | PrismaValue::String(s), ScalarType::Geometry) => Ok(PrismaValue::Json( + self.parse_geojson(selection_path, argument_path, &s).map(|_| s)?, + )), + // String coercion matchers (PrismaValue::String(s), ScalarType::JsonList) => { self.parse_json_list_from_str(selection_path, argument_path, &s) @@ -388,9 +401,6 @@ impl QueryDocumentParser { (PrismaValue::String(s), ScalarType::Json) => Ok(PrismaValue::Json( self.parse_json(selection_path, argument_path, &s).map(|_| s)?, )), - (PrismaValue::String(s), ScalarType::Geometry) => Ok(PrismaValue::Json( - self.parse_geojson(selection_path, argument_path, &s).map(|_| s)?, - )), (PrismaValue::String(s), ScalarType::DateTime) => self .parse_datetime(selection_path, argument_path, s.as_str()) .map(PrismaValue::DateTime), @@ -582,6 +592,28 @@ impl QueryDocumentParser { .map(PrismaValue::Json) } + fn to_geojson( + &self, + selection_path: &Path, + argument_path: &Path, + value: &ArgumentValue, + ) -> QueryParserResult { + serde_json::to_value(&value) + .map_err(geojson::Error::from) + .and_then(Geometry::try_from) + .map(|geom| Geometry::to_string(&geom)) + .map_err(|err| { + ValidationError::invalid_argument_value( + selection_path.segments(), + argument_path.segments(), + format!("{value:?}"), + "GeoJSON String", + Some(Box::new(err)), + ) + }) + .map(PrismaValue::Json) + } + fn parse_uuid(&self, selection_path: &Path, argument_path: &Path, s: &str) -> QueryParserResult { Uuid::parse_str(s).map_err(|err| { ValidationError::invalid_argument_value( From e813e61f5fabceaf14d4d04ac3881e7dd38d463b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aure=CC=80le=20Nitoref?= Date: Mon, 14 Oct 2024 16:08:08 +0200 Subject: [PATCH 103/103] Lint --- query-engine/core/src/query_document/parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/query-engine/core/src/query_document/parser.rs b/query-engine/core/src/query_document/parser.rs index a4e49d817782..c229157ca6f3 100644 --- a/query-engine/core/src/query_document/parser.rs +++ b/query-engine/core/src/query_document/parser.rs @@ -598,7 +598,7 @@ impl QueryDocumentParser { argument_path: &Path, value: &ArgumentValue, ) -> QueryParserResult { - serde_json::to_value(&value) + serde_json::to_value(value) .map_err(geojson::Error::from) .and_then(Geometry::try_from) .map(|geom| Geometry::to_string(&geom))