├── .github ├── CODEOWNERS ├── FUNDING.yml └── workflows │ └── deploy.yml ├── .gitignore ├── .npmrc ├── Cargo.lock ├── Cargo.toml ├── LICENSE.md ├── NOTICE ├── README.MD ├── assets ├── README.md └── package.json ├── crates ├── ast │ ├── builtin_connectors │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── cockroach_datamodel_connector.rs │ │ │ ├── cockroach_datamodel_connector │ │ │ ├── native_types.rs │ │ │ └── validations.rs │ │ │ ├── lib.rs │ │ │ ├── mongodb.rs │ │ │ ├── mongodb │ │ │ ├── mongodb_types.rs │ │ │ └── validations.rs │ │ │ ├── mssql_datamodel_connector.rs │ │ │ ├── mssql_datamodel_connector │ │ │ ├── native_types.rs │ │ │ └── validations.rs │ │ │ ├── mysql_datamodel_connector.rs │ │ │ ├── mysql_datamodel_connector │ │ │ ├── native_types.rs │ │ │ └── validations.rs │ │ │ ├── native_type_definition.rs │ │ │ ├── postgres_datamodel_connector.rs │ │ │ ├── postgres_datamodel_connector │ │ │ ├── datasource.rs │ │ │ ├── native_types.rs │ │ │ └── validations.rs │ │ │ └── sqlite_datamodel_connector.rs │ ├── diagnostics │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── collection.rs │ │ │ ├── error.rs │ │ │ ├── lib.rs │ │ │ ├── native_type_error_factory.rs │ │ │ ├── pretty_print.rs │ │ │ ├── span.rs │ │ │ └── warning.rs │ ├── parser_database │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── attributes.rs │ │ │ ├── attributes │ │ │ ├── default.rs │ │ │ ├── id.rs │ │ │ ├── map.rs │ │ │ ├── native_types.rs │ │ │ └── schema.rs │ │ │ ├── coerce_expression.rs │ │ │ ├── context.rs │ │ │ ├── context │ │ │ └── attributes.rs │ │ │ ├── interner.rs │ │ │ ├── lib.rs │ │ │ ├── names.rs │ │ │ ├── names │ │ │ └── reserved_model_names.rs │ │ │ ├── relations.rs │ │ │ ├── types.rs │ │ │ ├── types │ │ │ └── index_fields.rs │ │ │ ├── walkers.rs │ │ │ └── walkers │ │ │ ├── composite_type.rs │ │ │ ├── enum.rs │ │ │ ├── field.rs │ │ │ ├── index.rs │ │ │ ├── model.rs │ │ │ ├── model │ │ │ ├── primary_key.rs │ │ │ └── unique_criteria.rs │ │ │ ├── relation.rs │ │ │ ├── relation │ │ │ ├── implicit_many_to_many.rs │ │ │ ├── inline.rs │ │ │ ├── inline │ │ │ │ └── complete.rs │ │ │ └── two_way_embedded_many_to_many.rs │ │ │ ├── relation_field.rs │ │ │ └── scalar_field.rs │ ├── psl │ │ ├── Cargo.toml │ │ ├── build.rs │ │ ├── src │ │ │ └── lib.rs │ │ └── tests │ │ │ ├── attributes │ │ │ ├── arg_parsing.rs │ │ │ ├── builtin_attributes.rs │ │ │ ├── cockroachdb_sequence.rs │ │ │ ├── composite_index.rs │ │ │ ├── constraint_names_negative.rs │ │ │ ├── constraint_names_positive.rs │ │ │ ├── default_composite_negative.rs │ │ │ ├── default_composite_positive.rs │ │ │ ├── default_negative.rs │ │ │ ├── default_positive.rs │ │ │ ├── field_name_clash.rs │ │ │ ├── id_negative.rs │ │ │ ├── id_positive.rs │ │ │ ├── ignore_negative.rs │ │ │ ├── ignore_positive.rs │ │ │ ├── index_clustering.rs │ │ │ ├── index_negative.rs │ │ │ ├── index_positive.rs │ │ │ ├── map_positive.rs │ │ │ ├── mod.rs │ │ │ ├── postgres_indices.rs │ │ │ ├── postgres_indices │ │ │ │ ├── brin.rs │ │ │ │ ├── cockroachdb.rs │ │ │ │ ├── gin.rs │ │ │ │ ├── gist.rs │ │ │ │ └── spgist.rs │ │ │ ├── relations │ │ │ │ ├── many_to_many_negative.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── referential_actions.rs │ │ │ │ ├── referential_actions │ │ │ │ │ └── cycle_detection.rs │ │ │ │ ├── relations_negative.rs │ │ │ │ ├── relations_new.rs │ │ │ │ └── relations_positive.rs │ │ │ ├── unique_negative.rs │ │ │ ├── unique_positive.rs │ │ │ ├── updated_at_negative.rs │ │ │ └── updated_at_positive.rs │ │ │ ├── base │ │ │ ├── array_sugar.rs │ │ │ ├── base_types.rs │ │ │ ├── basic.rs │ │ │ ├── comments.rs │ │ │ ├── duplicates.rs │ │ │ └── mod.rs │ │ │ ├── capabilities │ │ │ ├── cockroachdb.rs │ │ │ ├── mod.rs │ │ │ ├── mysql.rs │ │ │ ├── postgres.rs │ │ │ ├── sqlite.rs │ │ │ └── sqlserver.rs │ │ │ ├── common │ │ │ ├── asserts.rs │ │ │ └── mod.rs │ │ │ ├── config │ │ │ ├── datasources.rs │ │ │ ├── generators.rs │ │ │ ├── mod.rs │ │ │ ├── nice_warnings.rs │ │ │ └── sources.rs │ │ │ ├── datamodel_tests.rs │ │ │ ├── functions │ │ │ ├── functionals_environment.rs │ │ │ ├── mod.rs │ │ │ ├── server_side_functions.rs │ │ │ └── string_interpolation.rs │ │ │ ├── panic_with_diff │ │ │ └── mod.rs │ │ │ ├── parsing │ │ │ ├── attributes.rs │ │ │ ├── comments.rs │ │ │ ├── expressions.rs │ │ │ ├── literals.rs │ │ │ ├── mod.rs │ │ │ ├── models.rs │ │ │ └── nice_errors.rs │ │ │ ├── reformat │ │ │ ├── mod.rs │ │ │ ├── reformat.rs │ │ │ └── reformat_implicit_relations.rs │ │ │ ├── reformat_tests.rs │ │ │ ├── reformatter │ │ │ ├── block_attribute_comments_are_preserved.prisma │ │ │ ├── block_attribute_comments_are_preserved.reformatted.prisma │ │ │ ├── catch_all_in_a_block_must_not_influence_table_layout.prisma │ │ │ ├── catch_all_in_a_block_must_not_influence_table_layout.reformatted.prisma │ │ │ ├── model_block_attributes_ordering.prisma │ │ │ ├── model_block_attributes_ordering.reformatted.prisma │ │ │ ├── model_field_attributes_ordering.prisma │ │ │ ├── model_field_attributes_ordering.reformatted.prisma │ │ │ ├── model_single_field.prisma │ │ │ ├── model_single_field.reformatted.prisma │ │ │ ├── optional_list_fields.prisma │ │ │ ├── optional_list_fields.reformatted.prisma │ │ │ ├── regression_add_relation_attribute_on_field_with_multi_byte_trailing_comment.prisma │ │ │ ├── regression_add_relation_attribute_on_field_with_multi_byte_trailing_comment.reformatted.prisma │ │ │ ├── relations │ │ │ │ ├── back_relation_fields_and_attribute_must_be_added_even_when_attribute_is_missing.prisma │ │ │ │ ├── back_relation_fields_and_attribute_must_be_added_even_when_attribute_is_missing.reformatted.prisma │ │ │ │ ├── back_relation_fields_must_be_added.prisma │ │ │ │ ├── back_relation_fields_must_be_added.reformatted.prisma │ │ │ │ ├── forward_relation_fields_must_be_added.prisma │ │ │ │ ├── forward_relation_fields_must_be_added.reformatted.prisma │ │ │ │ ├── native_types_in_missing_relation_fields.prisma │ │ │ │ └── native_types_in_missing_relation_fields.reformatted.prisma │ │ │ ├── trailing_comments_allowed_in_configuration_blocks.prisma │ │ │ ├── trailing_comments_allowed_in_configuration_blocks.reformatted.prisma │ │ │ ├── type_aliases.prisma │ │ │ └── type_aliases.reformatted.prisma │ │ │ ├── types │ │ │ ├── cockroachdb_native_types.rs │ │ │ ├── composite_types.rs │ │ │ ├── mod.rs │ │ │ ├── mongo_native_types.rs │ │ │ ├── mssql_native_types.rs │ │ │ ├── mysql_native_types.rs │ │ │ ├── negative.rs │ │ │ ├── positive.rs │ │ │ └── postgres_native_types.rs │ │ │ ├── validation │ │ │ ├── attributes │ │ │ │ ├── index │ │ │ │ │ ├── indexes_on_relation_fields_must_error.prisma │ │ │ │ │ ├── missing_index_warning │ │ │ │ │ │ ├── mongodb.prisma │ │ │ │ │ │ ├── relation_mode_foreign_keys.prisma │ │ │ │ │ │ └── relation_mode_prisma │ │ │ │ │ │ │ ├── one_field_at_at_unique.prisma │ │ │ │ │ │ │ ├── one_field_at_unique.prisma │ │ │ │ │ │ │ ├── one_field_no_index.prisma │ │ │ │ │ │ │ ├── three_fields_index_leftmost.prisma │ │ │ │ │ │ │ ├── three_fields_index_rightmost.prisma │ │ │ │ │ │ │ ├── three_fields_mixed_unique.prisma │ │ │ │ │ │ │ └── three_fields_no_index.prisma │ │ │ │ │ ├── mysql_missing_length.prisma │ │ │ │ │ ├── sql_server_disallows_compound_unique_length_prefix.prisma │ │ │ │ │ ├── sql_server_disallows_index_length_prefix.prisma │ │ │ │ │ ├── sqlite_disallows_unique_length_prefix.prisma │ │ │ │ │ ├── sqlserver_disallows_unique_length_prefix.prisma │ │ │ │ │ ├── string_field_names.prisma │ │ │ │ │ ├── unique_sort_order_as_string.prisma │ │ │ │ │ └── unknown_field.prisma │ │ │ │ ├── index_clustering │ │ │ │ │ ├── clustered_compound_unique_on_sqlite.prisma │ │ │ │ │ ├── id_and_index_clustering_together_not_allowed.prisma │ │ │ │ │ ├── id_and_unique_clustering_together_not_allowed.prisma │ │ │ │ │ ├── non_boolean_index_clustering.prisma │ │ │ │ │ ├── non_clustered_compound_id_sqlite.prisma │ │ │ │ │ ├── non_clustered_id_sqlite.prisma │ │ │ │ │ ├── on_mysql.prisma │ │ │ │ │ └── on_postgres.prisma │ │ │ │ ├── map │ │ │ │ │ ├── duplicate_models_with_map_on_both_sides.prisma │ │ │ │ │ ├── map_must_error_for_relation_fields.prisma │ │ │ │ │ ├── mongodb_field_map_cannot_contain_periods.prisma │ │ │ │ │ └── mongodb_field_map_cannot_start_with_dollar_sign.prisma │ │ │ │ ├── nanoid │ │ │ │ │ ├── require_int_argument.prisma │ │ │ │ │ ├── require_minimum_value.prisma │ │ │ │ │ ├── require_string_column.prisma │ │ │ │ │ ├── string_column_with_length_valid.prisma │ │ │ │ │ └── string_column_with_no_argument_valid.prisma │ │ │ │ ├── relation_mode │ │ │ │ │ ├── referential_integrity_attr_is_deprecated.prisma │ │ │ │ │ └── relation_mode_and_referential_integrity_cannot_cooccur.prisma │ │ │ │ └── schema │ │ │ │ │ ├── bad_schema_attribute.prisma │ │ │ │ │ ├── enums_in_different_schemas_with_same_mapped_name.prisma │ │ │ │ │ ├── enums_in_same_schema_with_same_mapped_name.prisma │ │ │ │ │ ├── missing_schema_annotations.prisma │ │ │ │ │ ├── multiple_schemas_valid.prisma │ │ │ │ │ ├── mysql_enums_do_not_have_a_schema.prisma │ │ │ │ │ ├── no_schema_attributes.prisma │ │ │ │ │ ├── non_existing_schema.prisma │ │ │ │ │ ├── on_sqlite.prisma │ │ │ │ │ ├── repeated_schema_attribute.prisma │ │ │ │ │ ├── tables_in_different_schemas_with_same_constraint_names.prisma │ │ │ │ │ ├── tables_in_different_schemas_with_same_mapped_name.prisma │ │ │ │ │ ├── tables_in_same_schema_with_same_constraint_names.prisma │ │ │ │ │ ├── tables_in_same_schema_with_same_mapped_name.prisma │ │ │ │ │ ├── with_single_schema.prisma │ │ │ │ │ ├── with_single_schema_mysql.prisma │ │ │ │ │ ├── with_single_schema_sqlserver.prisma │ │ │ │ │ └── without_preview_feature.prisma │ │ │ ├── capabilities │ │ │ │ ├── mongodb_does_not_support_autoincrement.prisma │ │ │ │ └── mongodb_supports_composite_types.prisma │ │ │ ├── cockroachdb │ │ │ │ └── negative_time_precision.prisma │ │ │ ├── composite_types │ │ │ │ ├── ignore_field_attribute_is_not_allowed.prisma │ │ │ │ ├── index_attributes_on_composite_types.prisma │ │ │ │ ├── map_field_attribute_is_allowed.prisma │ │ │ │ ├── relation_field_attribute_not_allowed.prisma │ │ │ │ └── unique_index_field_clash.prisma │ │ │ ├── datasource │ │ │ │ ├── duplicates_in_schemas.prisma │ │ │ │ └── schemas_array_with_non_string_values.prisma │ │ │ ├── mysql │ │ │ │ ├── set_default_no_warning_when_relation_mode_prisma.prisma │ │ │ │ ├── set_default_warning.prisma │ │ │ │ └── set_default_warning_when_relation_mode_foreignkeys.prisma │ │ │ ├── postgres │ │ │ │ └── negative_time_precision.prisma │ │ │ ├── postgres_extensions │ │ │ │ ├── extensions_are_not_numbers.prisma │ │ │ │ ├── extensions_are_not_strings.prisma │ │ │ │ ├── extensions_do_not_work_on_mongodb.prisma │ │ │ │ ├── extensions_do_not_work_on_mysql.prisma │ │ │ │ ├── extensions_do_not_work_on_sqlite.prisma │ │ │ │ ├── extensions_do_not_work_on_sqlserver.prisma │ │ │ │ ├── extensions_require_feature_flag.prisma │ │ │ │ ├── extensions_with_arguments.prisma │ │ │ │ ├── extensions_with_duplicate_arguments.prisma │ │ │ │ ├── extensions_with_float_arguments.prisma │ │ │ │ ├── extensions_with_garbage_arguments.prisma │ │ │ │ ├── extensions_with_unnamed_arguments.prisma │ │ │ │ ├── feature_flag.prisma │ │ │ │ ├── invalid_characters_in_name.prisma │ │ │ │ ├── simple_single_extension.prisma │ │ │ │ └── single_extension_does_not_need_an_array.prisma │ │ │ ├── postgres_indexes │ │ │ │ ├── brin │ │ │ │ │ ├── bit_minmax_no_native_type.prisma │ │ │ │ │ ├── bit_minmax_wrong_native_type.prisma │ │ │ │ │ ├── date_bloom_wrong_native_type.prisma │ │ │ │ │ ├── date_minmax_wrong_native_type.prisma │ │ │ │ │ ├── date_minmaxmulti_wrong_native_type.prisma │ │ │ │ │ ├── on_mysql.prisma │ │ │ │ │ ├── uuid_bloom_wrong_native_type.prisma │ │ │ │ │ ├── uuid_minmax_wrong_native_type.prisma │ │ │ │ │ ├── uuid_minmaxmulti_wrong_native_type.prisma │ │ │ │ │ ├── varbit_minmax_no_native_type.prisma │ │ │ │ │ └── varbit_minmax_wrong_native_type.prisma │ │ │ │ ├── gin │ │ │ │ │ ├── array_ops_default_ops.prisma │ │ │ │ │ ├── array_ops_invalid_index_type.prisma │ │ │ │ │ └── on_mysql.prisma │ │ │ │ └── spgist │ │ │ │ │ ├── inet_ops_with_wrong_index_type.prisma │ │ │ │ │ ├── inet_ops_with_wrong_prisma_type.prisma │ │ │ │ │ ├── no_ops_weird_type.prisma │ │ │ │ │ ├── on_mysql.prisma │ │ │ │ │ ├── only_single_column_allowed.prisma │ │ │ │ │ ├── text_ops_with_wrong_index_type.prisma │ │ │ │ │ └── text_ops_with_wrong_prisma_type.prisma │ │ │ ├── relations │ │ │ │ ├── mongodb │ │ │ │ │ ├── relation_same_native_type_1.prisma │ │ │ │ │ ├── relation_same_native_type_2.prisma │ │ │ │ │ └── relation_same_native_type_3.prisma │ │ │ │ ├── postgres │ │ │ │ │ ├── set_null_is_not_valid_on_mixed_fields_when_relation_mode_prisma.prisma │ │ │ │ │ ├── set_null_is_not_valid_on_required_fields_when_relation_mode_prisma.prisma │ │ │ │ │ ├── set_null_warns_on_mixed_fields.prisma │ │ │ │ │ └── set_null_warns_on_required_fields.prisma │ │ │ │ ├── relation_field_with_ignored_or_unspported_fields_does_not_need_ignore.prisma │ │ │ │ ├── set_null_is_not_valid_on_mixed_fields.prisma │ │ │ │ ├── set_null_is_not_valid_on_required_fields.prisma │ │ │ │ └── set_null_still_valid_on_optional_fields.prisma │ │ │ ├── types │ │ │ │ └── mongodb │ │ │ │ │ ├── invalid_bindata_usage_in_model.prisma │ │ │ │ │ ├── invalid_bindata_usage_in_type.prisma │ │ │ │ │ ├── invalid_bool_usage_in_model.prisma │ │ │ │ │ ├── invalid_bool_usage_in_type.prisma │ │ │ │ │ ├── invalid_date_usage_in_model.prisma │ │ │ │ │ ├── invalid_date_usage_in_type.prisma │ │ │ │ │ ├── invalid_double_usage_in_model.prisma │ │ │ │ │ ├── invalid_double_usage_in_type.prisma │ │ │ │ │ ├── invalid_int_usage_in_model.prisma │ │ │ │ │ ├── invalid_int_usage_in_type.prisma │ │ │ │ │ ├── invalid_json_usage_in_type.prisma │ │ │ │ │ ├── invalid_long_usage_in_model.prisma │ │ │ │ │ ├── invalid_long_usage_in_type.prisma │ │ │ │ │ ├── invalid_object_id_usage_in_model.prisma │ │ │ │ │ ├── invalid_object_id_usage_in_type.prisma │ │ │ │ │ ├── invalid_string_usage_in_model.prisma │ │ │ │ │ ├── invalid_string_usage_in_type.prisma │ │ │ │ │ ├── invalid_timestamp_usage_in_model.prisma │ │ │ │ │ └── invalid_timestamp_usage_in_type.prisma │ │ │ └── views │ │ │ │ ├── basic_view.prisma │ │ │ │ ├── duplicate_field.prisma │ │ │ │ ├── duplicate_view_model_names.prisma │ │ │ │ ├── duplicate_view_model_names_2.prisma │ │ │ │ ├── duplicate_view_names.prisma │ │ │ │ ├── field_name_starts_with_number.prisma │ │ │ │ ├── garbage_field_definition.prisma │ │ │ │ ├── multi_schema.prisma │ │ │ │ ├── multi_schema_no_schema_declaration.prisma │ │ │ │ ├── name_starts_with_number.prisma │ │ │ │ ├── no_preview_feature.prisma │ │ │ │ ├── no_unique.prisma │ │ │ │ └── reserved_name.prisma │ │ │ └── validation_tests.rs │ ├── psl_core │ │ ├── Cargo.toml │ │ ├── README.md │ │ └── src │ │ │ ├── common.rs │ │ │ ├── common │ │ │ └── preview_features.rs │ │ │ ├── configuration.rs │ │ │ ├── configuration │ │ │ ├── configuration_struct.rs │ │ │ ├── datasource.rs │ │ │ ├── env_vars.rs │ │ │ └── generator.rs │ │ │ ├── datamodel_connector.rs │ │ │ ├── datamodel_connector │ │ │ ├── capabilities.rs │ │ │ ├── constraint_names.rs │ │ │ ├── empty_connector.rs │ │ │ ├── filters.rs │ │ │ ├── native_types.rs │ │ │ ├── relation_mode.rs │ │ │ └── walker_ext_traits.rs │ │ │ ├── lib.rs │ │ │ ├── mcf.rs │ │ │ ├── mcf │ │ │ ├── generator.rs │ │ │ └── source.rs │ │ │ ├── reformat.rs │ │ │ ├── validate.rs │ │ │ └── validate │ │ │ ├── datasource_loader.rs │ │ │ ├── generator_loader.rs │ │ │ ├── validation_pipeline.rs │ │ │ └── validation_pipeline │ │ │ ├── context.rs │ │ │ ├── validations.rs │ │ │ └── validations │ │ │ ├── autoincrement.rs │ │ │ ├── composite_types.rs │ │ │ ├── constraint_namespace.rs │ │ │ ├── database_name.rs │ │ │ ├── datasource.rs │ │ │ ├── default_value.rs │ │ │ ├── enums.rs │ │ │ ├── fields.rs │ │ │ ├── indexes.rs │ │ │ ├── models.rs │ │ │ ├── names.rs │ │ │ ├── relation_fields.rs │ │ │ ├── relations.rs │ │ │ ├── relations │ │ │ ├── many_to_many.rs │ │ │ ├── many_to_many │ │ │ │ ├── embedded.rs │ │ │ │ └── implicit.rs │ │ │ ├── one_to_many.rs │ │ │ ├── one_to_one.rs │ │ │ └── visited_relation.rs │ │ │ └── views.rs │ └── schema_ast │ │ ├── Cargo.toml │ │ └── src │ │ ├── ast.rs │ │ ├── ast │ │ ├── argument.rs │ │ ├── attribute.rs │ │ ├── comment.rs │ │ ├── composite_type.rs │ │ ├── config.rs │ │ ├── enum.rs │ │ ├── expression.rs │ │ ├── field.rs │ │ ├── find_at_position.rs │ │ ├── generator_config.rs │ │ ├── identifier.rs │ │ ├── indentation_type.rs │ │ ├── model.rs │ │ ├── newline_type.rs │ │ ├── source_config.rs │ │ ├── top.rs │ │ └── traits.rs │ │ ├── lib.rs │ │ ├── parser.rs │ │ ├── parser │ │ ├── datamodel.pest │ │ ├── helpers.rs │ │ ├── parse_arguments.rs │ │ ├── parse_attribute.rs │ │ ├── parse_comments.rs │ │ ├── parse_composite_type.rs │ │ ├── parse_enum.rs │ │ ├── parse_expression.rs │ │ ├── parse_field.rs │ │ ├── parse_model.rs │ │ ├── parse_schema.rs │ │ ├── parse_source_and_generator.rs │ │ ├── parse_types.rs │ │ └── parse_view.rs │ │ ├── reformat.rs │ │ ├── renderer.rs │ │ ├── renderer │ │ └── table.rs │ │ └── source_file.rs ├── format │ ├── turboprisma_fmt │ │ ├── Cargo.toml │ │ ├── build.rs │ │ ├── schema.prisma │ │ └── src │ │ │ ├── actions.rs │ │ │ ├── code_actions.rs │ │ │ ├── code_actions │ │ │ ├── multi_schema.rs │ │ │ ├── relation_mode.rs │ │ │ └── relations.rs │ │ │ ├── format.rs │ │ │ ├── get_config.rs │ │ │ ├── get_dmmf.rs │ │ │ ├── lib.rs │ │ │ ├── lint.rs │ │ │ ├── main.rs │ │ │ ├── native.rs │ │ │ ├── preview.rs │ │ │ ├── text_document_completion.rs │ │ │ └── validate.rs │ └── turboprisma_fmt_wasm │ │ ├── Cargo.toml │ │ ├── LICENSE.md │ │ ├── README.md │ │ ├── package.json │ │ └── src │ │ └── lib.rs ├── libs │ └── prisma_value │ │ ├── Cargo.toml │ │ └── src │ │ ├── arithmetic.rs │ │ ├── error.rs │ │ └── lib.rs ├── query_engine │ ├── dml │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── composite_type.rs │ │ │ ├── datamodel.rs │ │ │ ├── default_value.rs │ │ │ ├── field.rs │ │ │ ├── lib.rs │ │ │ ├── lift.rs │ │ │ ├── model.rs │ │ │ ├── native_type_instance.rs │ │ │ ├── relation_info.rs │ │ │ ├── scalars.rs │ │ │ └── traits.rs │ ├── dmmf │ │ ├── Cargo.toml │ │ ├── src │ │ │ ├── ast_builders │ │ │ │ ├── datamodel_ast_builder.rs │ │ │ │ ├── mod.rs │ │ │ │ └── schema_ast_builder │ │ │ │ │ ├── enum_renderer.rs │ │ │ │ │ ├── field_renderer.rs │ │ │ │ │ ├── mod.rs │ │ │ │ │ ├── object_renderer.rs │ │ │ │ │ ├── schema_renderer.rs │ │ │ │ │ └── type_renderer.rs │ │ │ ├── lib.rs │ │ │ ├── serialization_ast │ │ │ │ ├── datamodel_ast.rs │ │ │ │ ├── mappings_ast.rs │ │ │ │ ├── mod.rs │ │ │ │ └── schema_ast.rs │ │ │ ├── test-schemas │ │ │ │ └── sqlite_ignore.prisma │ │ │ └── tests.rs │ │ └── test_files │ │ │ ├── functions.json │ │ │ ├── functions.prisma │ │ │ ├── general.json │ │ │ ├── general.prisma │ │ │ ├── ignore.json │ │ │ ├── ignore.prisma │ │ │ ├── source.json │ │ │ ├── source.prisma │ │ │ ├── source_with_comments.json │ │ │ ├── source_with_comments.prisma │ │ │ ├── source_with_generator.json │ │ │ ├── source_with_generator.prisma │ │ │ ├── views.json │ │ │ ├── views.prisma │ │ │ ├── without_relation_name.json │ │ │ └── without_relation_name.prisma │ ├── prisma_models │ │ ├── Cargo.toml │ │ ├── src │ │ │ ├── composite_type.rs │ │ │ ├── convert.rs │ │ │ ├── error.rs │ │ │ ├── field │ │ │ │ ├── composite.rs │ │ │ │ ├── mod.rs │ │ │ │ ├── relation.rs │ │ │ │ └── scalar.rs │ │ │ ├── field_selection.rs │ │ │ ├── fields.rs │ │ │ ├── internal_data_model.rs │ │ │ ├── lib.rs │ │ │ ├── model.rs │ │ │ ├── order_by.rs │ │ │ ├── parent_container.rs │ │ │ ├── pk.rs │ │ │ ├── prelude.rs │ │ │ ├── prisma_value_ext.rs │ │ │ ├── projections │ │ │ │ ├── mod.rs │ │ │ │ └── model_projection.rs │ │ │ ├── record.rs │ │ │ ├── relation.rs │ │ │ ├── selection_result.rs │ │ │ └── zipper.rs │ │ └── tests │ │ │ └── datamodel_converter_tests.rs │ ├── schema │ │ ├── Cargo.toml │ │ └── src │ │ │ ├── enum_type.rs │ │ │ ├── input_types.rs │ │ │ ├── lib.rs │ │ │ ├── output_types.rs │ │ │ ├── query_schema.rs │ │ │ └── renderer.rs │ └── schema_builder │ │ ├── Cargo.toml │ │ ├── benches │ │ ├── noalyss_folder.prisma │ │ ├── odoo.prisma │ │ ├── schema_builder_bench.rs │ │ └── standupbot.prisma │ │ └── src │ │ ├── cache.rs │ │ ├── constants.rs │ │ ├── enum_types.rs │ │ ├── input_types │ │ ├── fields │ │ │ ├── arguments.rs │ │ │ ├── data_input_mapper │ │ │ │ ├── create.rs │ │ │ │ ├── mod.rs │ │ │ │ └── update.rs │ │ │ ├── field_filter_types.rs │ │ │ ├── field_ref_type.rs │ │ │ ├── input_fields.rs │ │ │ └── mod.rs │ │ ├── mod.rs │ │ └── objects │ │ │ ├── connect_or_create_objects.rs │ │ │ ├── filter_objects.rs │ │ │ ├── mod.rs │ │ │ ├── order_by_objects.rs │ │ │ ├── update_many_objects.rs │ │ │ ├── update_one_objects.rs │ │ │ └── upsert_objects.rs │ │ ├── lib.rs │ │ ├── mutations │ │ ├── create_many.rs │ │ ├── create_one.rs │ │ └── mod.rs │ │ ├── output_types │ │ ├── aggregation │ │ │ ├── group_by.rs │ │ │ ├── mod.rs │ │ │ └── plain.rs │ │ ├── field.rs │ │ ├── mod.rs │ │ ├── mutation_type.rs │ │ ├── objects │ │ │ ├── composite.rs │ │ │ ├── mod.rs │ │ │ └── model.rs │ │ └── query_type.rs │ │ └── utils.rs ├── turboprisma_cli │ ├── Cargo.toml │ └── src │ │ ├── args.rs │ │ ├── commands │ │ ├── format.rs │ │ ├── init.rs │ │ ├── mod.rs │ │ ├── validate.rs │ │ └── version.rs │ │ ├── env_parser.rs │ │ ├── main.rs │ │ └── utils │ │ ├── env.rs │ │ ├── install.rs │ │ ├── mod.rs │ │ └── schema.rs └── turboprisma_vm │ ├── Cargo.toml │ └── src │ └── main.rs ├── package.json ├── packages ├── turboprisma-vm │ ├── LICENSE │ ├── README.MD │ ├── package.json │ ├── postInstall.js │ └── turboprisma_cli └── turboprisma │ ├── LICENSE │ ├── README.MD │ ├── package.json │ ├── postInstall.js │ └── turboprisma_cli ├── pnpm-lock.yaml ├── pnpm-workspace.yaml └── tsconfig.json /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @DavidHancu @leohaarmann -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: davidhancu -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | node_modules 3 | 4 | # not ready yet 5 | /packages/generator 6 | /packages/*/target 7 | 8 | prisma 9 | .env -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | auto-install-peers = true 2 | hoist = false -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | #"crates/ast/turboprisma_ast", 4 | "crates/turboprisma_cli", 5 | "crates/ast/*", 6 | "crates/libs/*", 7 | "crates/format/*", 8 | "crates/query_engine/*", 9 | "crates/turboprisma_vm" 10 | ] -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Parts of this project have been modified from the Prisma Engines (available at https://github.com/prisma/prisma-engines), made 2 | available via GitHub with an Apache-2.0 license by Prisma Data, Inc. -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 |

Turboprisma

9 |
10 | 11 | 12 | 13 |
14 |
15 | What is Turboprisma? 16 |   •   17 | Links 18 | 19 |
20 |
21 |
22 | 23 | ## What is Turboprisma? 24 | 25 | Turboprisma is a fast and performant Prisma runtime that provides an unified access framework, abstractions and new features on top of the Prisma schema, CLI and tools. It is fully developed in Rust, allowing for extreme speeds and optimizations which are just not possible with Prisma. 26 | 27 | ## Links 28 | 29 | Check out our API Documentation - [API Documentation](https://turboprisma.js.org/docs) 30 | 31 | Get Started with Turboprisma - [Getting Started](https://turboprisma.js.org/docs/getting-started) -------------------------------------------------------------------------------- /assets/README.md: -------------------------------------------------------------------------------- 1 | # `turboprisma` 2 | 3 | This is a platform-specific binary for Turboprisma, a Prisma Runtime. See https://turboprisma.js.org for details. -------------------------------------------------------------------------------- /assets/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "RINSERT_NAMER", 3 | "version": "RINSERT_VERSIONR", 4 | "description": "A platform binary for Turboprisma, a Prisma Runtime.", 5 | "repository": "https://github.com/DavidHancu/turboprisma", 6 | "bugs": "https://github.com/DavidHancu/turboprisma/issues", 7 | "homepage": "https://turboprisma.js.org", 8 | "license": "Apache-2.0", 9 | "os": [ 10 | "RINSERT_OSR" 11 | ], 12 | "cpu": [ 13 | "RINSERT_CPUR" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /crates/ast/builtin_connectors/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "builtin_psl_connectors" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | psl_core = { path = "../psl_core" } 8 | 9 | connection-string = "0.1" 10 | either = "1.6.1" 11 | enumflags2 = "0.7" 12 | indoc = "1" 13 | lsp-types = "0.91.1" 14 | once_cell = "1.3" 15 | regex = "1" 16 | -------------------------------------------------------------------------------- /crates/ast/builtin_connectors/src/cockroach_datamodel_connector/native_types.rs: -------------------------------------------------------------------------------- 1 | crate::native_type_definition! { 2 | CockroachType; 3 | Bit(Option) -> String, 4 | Bool -> Boolean, 5 | Bytes -> Bytes, 6 | Char(Option) -> String, 7 | Date -> DateTime, 8 | Decimal(Option<(u32, u32)>) -> Decimal, 9 | Float4 -> Float, 10 | Float8 -> Float, 11 | Inet -> String, 12 | Int2 -> Int, 13 | Int4 -> Int, 14 | Int8 -> BigInt, 15 | JsonB -> Json, 16 | Oid -> Int, 17 | CatalogSingleChar -> String, 18 | String(Option) -> String, 19 | Time(Option) -> DateTime, 20 | Timestamp(Option) -> DateTime, 21 | Timestamptz(Option) -> DateTime, 22 | Timetz(Option) -> DateTime, 23 | Uuid -> String, 24 | VarBit(Option) -> String, 25 | } 26 | -------------------------------------------------------------------------------- /crates/ast/builtin_connectors/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(rust_2018_idioms, unsafe_code)] 2 | #![allow(clippy::derive_partial_eq_without_eq)] 3 | 4 | pub mod cockroach_datamodel_connector; 5 | 6 | pub use cockroach_datamodel_connector::CockroachType; 7 | pub use mongodb::MongoDbType; 8 | pub use mssql_datamodel_connector::{MsSqlType, MsSqlTypeParameter}; 9 | pub use mysql_datamodel_connector::MySqlType; 10 | pub use postgres_datamodel_connector::{PostgresDatasourceProperties, PostgresType}; 11 | 12 | mod mongodb; 13 | mod mssql_datamodel_connector; 14 | mod mysql_datamodel_connector; 15 | mod native_type_definition; 16 | mod postgres_datamodel_connector; 17 | mod sqlite_datamodel_connector; 18 | 19 | use psl_core::{datamodel_connector::Connector, ConnectorRegistry}; 20 | 21 | pub const POSTGRES: &'static dyn Connector = &postgres_datamodel_connector::PostgresDatamodelConnector; 22 | pub const COCKROACH: &'static dyn Connector = &cockroach_datamodel_connector::CockroachDatamodelConnector; 23 | pub const MYSQL: &'static dyn Connector = &mysql_datamodel_connector::MySqlDatamodelConnector; 24 | pub const SQLITE: &'static dyn Connector = &sqlite_datamodel_connector::SqliteDatamodelConnector; 25 | pub const MSSQL: &'static dyn Connector = &mssql_datamodel_connector::MsSqlDatamodelConnector; 26 | pub const MONGODB: &'static dyn Connector = &mongodb::MongoDbDatamodelConnector; 27 | 28 | pub const BUILTIN_CONNECTORS: ConnectorRegistry = &[POSTGRES, MYSQL, SQLITE, MSSQL, COCKROACH, MONGODB]; 29 | -------------------------------------------------------------------------------- /crates/ast/builtin_connectors/src/mysql_datamodel_connector/native_types.rs: -------------------------------------------------------------------------------- 1 | crate::native_type_definition! { 2 | /// The MySQL native type enum. 3 | MySqlType; 4 | Int -> Int, 5 | UnsignedInt -> Int, 6 | SmallInt -> Int, 7 | UnsignedSmallInt -> Int, 8 | TinyInt -> Boolean | Int, 9 | UnsignedTinyInt -> Boolean | Int, 10 | MediumInt -> Int, 11 | UnsignedMediumInt -> Int, 12 | BigInt -> BigInt, 13 | Decimal(Option<(u32, u32)>) -> Decimal, 14 | UnsignedBigInt -> BigInt, 15 | Float -> Float, 16 | Double -> Float, 17 | Bit(u32) -> Boolean | Bytes, 18 | Char(u32) -> String, 19 | VarChar(u32) -> String, 20 | Binary(u32) -> Bytes, 21 | VarBinary(u32) -> Bytes, 22 | TinyBlob -> Bytes, 23 | Blob -> Bytes, 24 | MediumBlob -> Bytes, 25 | LongBlob -> Bytes, 26 | TinyText -> String, 27 | Text -> String, 28 | MediumText -> String, 29 | LongText -> String, 30 | Date -> DateTime, 31 | Time(Option) -> DateTime, 32 | DateTime(Option) -> DateTime, 33 | Timestamp(Option) -> DateTime, 34 | Year -> Int, 35 | Json -> Json, 36 | } 37 | 38 | impl MySqlType { 39 | /// The user-defined precision for timestamp columns, where applicable. 40 | pub fn timestamp_precision(&self) -> Option { 41 | match self { 42 | MySqlType::Time(n) | MySqlType::DateTime(n) | MySqlType::Timestamp(n) => *n, 43 | _ => None, 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /crates/ast/builtin_connectors/src/postgres_datamodel_connector/native_types.rs: -------------------------------------------------------------------------------- 1 | crate::native_type_definition! { 2 | PostgresType; 3 | SmallInt -> Int, 4 | Integer -> Int, 5 | BigInt -> BigInt, 6 | Decimal(Option<(u32, u32)>) -> Decimal, 7 | Money -> Decimal, 8 | Inet -> String, 9 | Oid -> Int, 10 | Citext -> String, 11 | Real -> Float, 12 | DoublePrecision -> Float, 13 | VarChar(Option) -> String, 14 | Char(Option) -> String, 15 | Text -> String, 16 | ByteA -> Bytes, 17 | Timestamp(Option) -> DateTime, 18 | Timestamptz(Option) -> DateTime, 19 | Date -> DateTime, 20 | Time(Option) -> DateTime, 21 | Timetz(Option) -> DateTime, 22 | Boolean -> Boolean, 23 | Bit(Option) -> String, 24 | VarBit(Option) -> String, 25 | Uuid -> String, 26 | Xml -> String, 27 | Json -> Json, 28 | JsonB -> Json, 29 | } 30 | -------------------------------------------------------------------------------- /crates/ast/diagnostics/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "diagnostics" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | colored = "2" 10 | pest = "2.1.3" 11 | indoc = "1" -------------------------------------------------------------------------------- /crates/ast/diagnostics/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod collection; 2 | mod error; 3 | mod native_type_error_factory; 4 | mod pretty_print; 5 | mod span; 6 | mod warning; 7 | 8 | pub use collection::Diagnostics; 9 | pub use error::DatamodelError; 10 | pub use native_type_error_factory::NativeTypeErrorFactory; 11 | pub use span::Span; 12 | pub use warning::DatamodelWarning; -------------------------------------------------------------------------------- /crates/ast/diagnostics/src/span.rs: -------------------------------------------------------------------------------- 1 | /// Represents a location in a datamodel's text representation. 2 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 3 | pub struct Span { 4 | pub start: usize, 5 | pub end: usize, 6 | } 7 | 8 | impl Span { 9 | /// Constructor. 10 | pub fn new(start: usize, end: usize) -> Span { 11 | Span { start, end } 12 | } 13 | 14 | /// Creates a new empty span. 15 | pub fn empty() -> Span { 16 | Span { start: 0, end: 0 } 17 | } 18 | 19 | /// Is the given position inside the span? (boundaries included) 20 | pub fn contains(&self, position: usize) -> bool { 21 | position >= self.start && position <= self.end 22 | } 23 | 24 | /// Is the given span overlapping with the current span. 25 | pub fn overlaps(self, other: Span) -> bool { 26 | self.contains(other.start) || self.contains(other.end) 27 | } 28 | } 29 | 30 | impl From> for Span { 31 | fn from(s: pest::Span<'_>) -> Self { 32 | Span { 33 | start: s.start(), 34 | end: s.end(), 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /crates/ast/parser_database/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "parser_database" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | diagnostics = { path = "../diagnostics" } 8 | schema_ast = { path = "../schema_ast" } 9 | 10 | enumflags2 = "0.7" 11 | indexmap = "1.8.0" 12 | either = "1.6.1" 13 | -------------------------------------------------------------------------------- /crates/ast/parser_database/src/attributes/native_types.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | ast, 3 | types::{CompositeTypeField, ScalarField}, 4 | StringId, 5 | }; 6 | 7 | pub(super) fn visit_model_field_native_type_attribute( 8 | datasource_name: StringId, 9 | type_name: StringId, 10 | attr: &ast::Attribute, 11 | scalar_field: &mut ScalarField, 12 | ) { 13 | let args = &attr.arguments; 14 | let args: Vec = args.arguments.iter().map(|arg| arg.value.to_string()).collect(); 15 | 16 | scalar_field.native_type = Some((datasource_name, type_name, args, attr.span)) 17 | } 18 | 19 | pub(super) fn visit_composite_type_field_native_type_attribute( 20 | datasource_name: StringId, 21 | type_name: StringId, 22 | attr: &ast::Attribute, 23 | composite_type_field: &mut CompositeTypeField, 24 | ) { 25 | let args = &attr.arguments; 26 | let args: Vec = args.arguments.iter().map(|arg| arg.value.to_string()).collect(); 27 | 28 | composite_type_field.native_type = Some((datasource_name, type_name, args, attr.span)) 29 | } 30 | -------------------------------------------------------------------------------- /crates/ast/parser_database/src/attributes/schema.rs: -------------------------------------------------------------------------------- 1 | use crate::{ast, coerce, context::*, types::*, StringId}; 2 | 3 | pub(super) fn model(model_attributes: &mut ModelAttributes, ctx: &mut Context<'_>) { 4 | model_attributes.schema = visit_schema_attribute(ctx); 5 | } 6 | 7 | pub(super) fn r#enum(enum_attributes: &mut EnumAttributes, ctx: &mut Context<'_>) { 8 | enum_attributes.schema = visit_schema_attribute(ctx); 9 | } 10 | 11 | fn visit_schema_attribute(ctx: &mut Context<'_>) -> Option<(StringId, ast::Span)> { 12 | let arg = match ctx.visit_default_arg("map") { 13 | Ok(arg) => arg, 14 | Err(err) => { 15 | ctx.push_error(err); 16 | return None; 17 | } 18 | }; 19 | let name = coerce::string(arg, ctx.diagnostics)?; 20 | Some((ctx.interner.intern(name), arg.span())) 21 | } 22 | -------------------------------------------------------------------------------- /crates/ast/parser_database/src/context/attributes.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use crate::interner::StringId; 3 | 4 | #[derive(Default, Debug)] 5 | pub(super) struct AttributesValidationState { 6 | /// The attributes list being validated. 7 | pub(super) attributes: Vec, 8 | pub(super) unused_attributes: HashSet, // the _remaining_ attributes 9 | 10 | /// The attribute being validated. 11 | pub(super) attribute: Option, 12 | pub(super) args: HashMap, usize>, // the _remaining_ arguments of `attribute` 13 | } 14 | 15 | impl AttributesValidationState { 16 | pub(super) fn extend_attributes(&mut self, attributes: ast::AttributeContainer, ast: &ast::SchemaAst) { 17 | let attribute_ids = (0..ast[attributes].len()).map(|idx| ast::AttributeId::new_in_container(attributes, idx)); 18 | self.unused_attributes.extend(attribute_ids); 19 | 20 | self.attributes.push(attributes); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /crates/ast/parser_database/src/interner.rs: -------------------------------------------------------------------------------- 1 | //! An extremely simple, non-threadsafe string interner to reduce the memory usage and the 2 | //! allocation pressure of ParserDatabase. 3 | //! 4 | //! The StringIds returned by `intern` are only valid for this specific instance of the interner 5 | //! they were interned with. 6 | 7 | use indexmap::IndexSet; 8 | 9 | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] 10 | pub(crate) struct StringId(usize); 11 | 12 | #[derive(Default)] 13 | pub(crate) struct StringInterner { 14 | map: IndexSet, 15 | } 16 | 17 | impl StringInterner { 18 | pub(crate) fn get(&self, id: StringId) -> Option<&str> { 19 | self.map.get_index(id.0).map(|s| s.as_str()) 20 | } 21 | 22 | /// Get an already-interned string. 23 | pub(crate) fn lookup(&self, s: &str) -> Option { 24 | self.map.get_index_of(s).map(StringId) 25 | } 26 | 27 | pub(crate) fn intern(&mut self, s: &str) -> StringId { 28 | if let Some(id) = self.lookup(s) { 29 | id 30 | } else { 31 | let (idx, is_new) = self.map.insert_full(s.to_owned()); 32 | debug_assert!(is_new); 33 | StringId(idx) 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /crates/ast/psl/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "psl" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | builtin_psl_connectors = { path = "../builtin_connectors" } 8 | psl_core = { path = "../psl_core" } 9 | 10 | [dev-dependencies] 11 | dissimilar = "1.0.4" 12 | dml = { path = "../../query_engine/dml" } 13 | expect-test = "1.1.0" 14 | indoc = "1" 15 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/attributes/map_positive.rs: -------------------------------------------------------------------------------- 1 | use crate::common::*; 2 | 3 | #[test] 4 | fn map_attribute() { 5 | let dml = r#" 6 | model User { 7 | id Int @id 8 | firstName String @map("first_name") 9 | 10 | @@map("user") 11 | } 12 | 13 | model Post { 14 | id Int @id 15 | text String @map(name: "post_text") 16 | 17 | @@map(name: "posti") 18 | } 19 | "#; 20 | 21 | let schema = parse(dml); 22 | let user_model = schema.assert_has_model("User").assert_with_db_name("user"); 23 | user_model 24 | .assert_has_scalar_field("firstName") 25 | .assert_with_db_name("first_name"); 26 | 27 | let post_model = schema.assert_has_model("Post").assert_with_db_name("posti"); 28 | post_model 29 | .assert_has_scalar_field("text") 30 | .assert_with_db_name("post_text"); 31 | } 32 | 33 | #[test] 34 | fn map_on_composite_type_field() { 35 | let dml = r#" 36 | datasource db { 37 | provider = "mongodb" 38 | url = "mongodb://" 39 | } 40 | 41 | type Address { 42 | fullName String @map("full_name") 43 | } 44 | "#; 45 | 46 | let schema = parse(dml); 47 | let address_type = &schema.composite_types[0]; 48 | assert_eq!(address_type.fields[0].database_name.as_deref(), Some("full_name")); 49 | } 50 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/attributes/mod.rs: -------------------------------------------------------------------------------- 1 | mod arg_parsing; 2 | mod builtin_attributes; 3 | mod cockroachdb_sequence; 4 | mod composite_index; 5 | mod constraint_names_negative; 6 | mod constraint_names_positive; 7 | mod default_composite_negative; 8 | mod default_composite_positive; 9 | mod default_negative; 10 | mod default_positive; 11 | mod field_name_clash; 12 | mod id_negative; 13 | mod id_positive; 14 | mod ignore_negative; 15 | mod ignore_positive; 16 | mod index_clustering; 17 | mod index_negative; 18 | mod index_positive; 19 | mod map_positive; 20 | mod postgres_indices; 21 | mod relations; 22 | mod unique_negative; 23 | mod unique_positive; 24 | mod updated_at_negative; 25 | mod updated_at_positive; 26 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/attributes/relations/mod.rs: -------------------------------------------------------------------------------- 1 | mod many_to_many_negative; 2 | mod referential_actions; 3 | mod relations_negative; 4 | mod relations_new; 5 | mod relations_positive; 6 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/attributes/updated_at_positive.rs: -------------------------------------------------------------------------------- 1 | use crate::common::*; 2 | 3 | #[test] 4 | fn should_apply_updated_at_attribute() { 5 | let dml = r#" 6 | model User { 7 | id Int @id 8 | lastSeen DateTime @updatedAt 9 | } 10 | "#; 11 | 12 | let schema = parse(dml); 13 | let user_model = schema.assert_has_model("User"); 14 | user_model 15 | .assert_has_scalar_field("lastSeen") 16 | .assert_base_type(&ScalarType::DateTime) 17 | .assert_is_updated_at(true); 18 | user_model.assert_has_scalar_field("id").assert_is_updated_at(false); 19 | } 20 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/base/array_sugar.rs: -------------------------------------------------------------------------------- 1 | use crate::common::*; 2 | 3 | #[test] 4 | fn should_treat_single_values_as_arrays_of_length_one() { 5 | let dml = r#" 6 | model User { 7 | id Int @id 8 | posts Post[] 9 | } 10 | 11 | model Post { 12 | id Int @id 13 | userId Int 14 | 15 | user User @relation(fields: userId, references: id) 16 | } 17 | "#; 18 | 19 | let schema = parse_schema(dml); 20 | 21 | let user_model = schema.assert_has_model("User"); 22 | let post_model = schema.assert_has_model("Post"); 23 | post_model 24 | .assert_has_relation_field("user") 25 | .assert_relation_to(user_model.id); 26 | } 27 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/base/mod.rs: -------------------------------------------------------------------------------- 1 | mod array_sugar; 2 | mod base_types; 3 | mod basic; 4 | mod comments; 5 | mod duplicates; 6 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/capabilities/mod.rs: -------------------------------------------------------------------------------- 1 | mod cockroachdb; 2 | mod mysql; 3 | mod postgres; 4 | mod sqlite; 5 | mod sqlserver; 6 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/config/mod.rs: -------------------------------------------------------------------------------- 1 | mod datasources; 2 | mod generators; 3 | mod nice_warnings; 4 | mod sources; 5 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/config/nice_warnings.rs: -------------------------------------------------------------------------------- 1 | use crate::common::*; 2 | use psl::diagnostics::{DatamodelWarning, Span}; 3 | 4 | #[test] 5 | fn nice_warning_for_deprecated_generator_preview_feature() { 6 | let schema = r#" 7 | generator client { 8 | provider = "prisma-client-js" 9 | previewFeatures = ["middlewares"] 10 | } 11 | "#; 12 | 13 | let res = psl::parse_configuration(schema).unwrap(); 14 | 15 | res.warnings.assert_is(DatamodelWarning::new_feature_deprecated( 16 | "middlewares", 17 | Span::new(88, 103), 18 | )); 19 | } 20 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/functions/functionals_environment.rs: -------------------------------------------------------------------------------- 1 | use crate::common::parse; 2 | 3 | #[test] 4 | fn skipping_of_env_vars() { 5 | let dml = r#" 6 | datasource db { 7 | provider = "postgresql" 8 | url = env("POSTGRES_URL") 9 | } 10 | 11 | model User { 12 | id Int @id 13 | tags String[] 14 | } 15 | "#; 16 | 17 | // must not fail without env var 18 | parse(dml); 19 | } 20 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/functions/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod functionals_environment; 2 | pub mod server_side_functions; 3 | pub mod string_interpolation; 4 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/functions/string_interpolation.rs: -------------------------------------------------------------------------------- 1 | use crate::common::*; 2 | use dml::{self, PrismaValue, ScalarType}; 3 | 4 | #[test] 5 | fn should_not_remove_whitespace() { 6 | let dml = r#" 7 | model User { 8 | id Int @id 9 | firstName String @default("This is a string with whitespace") 10 | } 11 | "#; 12 | 13 | let schema = parse(dml); 14 | let user_model = schema.assert_has_model("User"); 15 | user_model 16 | .assert_has_scalar_field("firstName") 17 | .assert_base_type(&ScalarType::String) 18 | .assert_default_value(dml::DefaultValue::new_single(PrismaValue::String(String::from( 19 | "This is a string with whitespace", 20 | )))); 21 | } 22 | 23 | #[test] 24 | fn should_not_try_to_interpret_comments_in_strings() { 25 | let dml = r#" 26 | model User { 27 | id Int @id 28 | firstName String @default("This is a string with a // Comment") 29 | } 30 | "#; 31 | 32 | let schema = parse(dml); 33 | let user_model = schema.assert_has_model("User"); 34 | user_model 35 | .assert_has_scalar_field("firstName") 36 | .assert_base_type(&ScalarType::String) 37 | .assert_default_value(dml::DefaultValue::new_single(PrismaValue::String(String::from( 38 | "This is a string with a // Comment", 39 | )))); 40 | } 41 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/panic_with_diff/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) fn panic_with_diff(expected: &str, found: &str) { 2 | let chunks = dissimilar::diff(expected, found); 3 | let diff = format_chunks(chunks); 4 | panic!( 5 | r#" 6 | Snapshot comparison failed. Run the test again with UPDATE_EXPECT=1 in the environment to update the snapshot. 7 | 8 | ===== EXPECTED ==== 9 | {expected} 10 | ====== FOUND ====== 11 | {found} 12 | ======= DIFF ====== 13 | {diff} 14 | "# 15 | ); 16 | } 17 | 18 | fn format_chunks(chunks: Vec>) -> String { 19 | let mut buf = String::new(); 20 | for chunk in chunks { 21 | let formatted = match chunk { 22 | dissimilar::Chunk::Equal(text) => text.into(), 23 | dissimilar::Chunk::Delete(text) => format!("\x1b[41m{text}\x1b[0m"), 24 | dissimilar::Chunk::Insert(text) => format!("\x1b[42m{text}\x1b[0m"), 25 | }; 26 | buf.push_str(&formatted); 27 | } 28 | buf 29 | } 30 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/parsing/comments.rs: -------------------------------------------------------------------------------- 1 | use crate::common::*; 2 | 3 | #[test] 4 | fn trailing_comments_allowed_in_configuration_blocks() { 5 | let schema = r#" 6 | datasource db { 7 | provider = "postgres" // "mysql" | "sqlite" ... 8 | url = env("TEST_POSTGRES_URI") 9 | relationMode = "prisma" // = on or set to "foreignKeys" to turn off emulation 10 | } 11 | 12 | generator js { 13 | provider = "prisma-client-js" // optional 14 | previewFeatures = ["referentialIntegrity"] // [] 15 | } 16 | "#; 17 | assert_valid(schema); 18 | } 19 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/parsing/mod.rs: -------------------------------------------------------------------------------- 1 | mod attributes; 2 | mod comments; 3 | mod expressions; 4 | mod literals; 5 | mod models; 6 | mod nice_errors; 7 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformat/mod.rs: -------------------------------------------------------------------------------- 1 | mod reformat; 2 | mod reformat_implicit_relations; 3 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformatter/block_attribute_comments_are_preserved.prisma: -------------------------------------------------------------------------------- 1 | model MyModel { 2 | // Example Comment 3 | field1 Int // Comment Field 1 4 | field2 Int // Comment Field 2 5 | field3 Int // Comment Field 3 6 | 7 | // This comment should stay here. 8 | @@unique([field1, field2]) // younique 9 | 10 | // This one must stay too. 11 | @@unique([field1, field3]) // there too 12 | } 13 | 14 | type YourType { 15 | // Example Comment 16 | field1 Int // Comment Field 1 17 | field2 Int // Comment Field 2 18 | field3 Int // Comment Field 3 19 | 20 | // This comment should stay here. 21 | @@unique([field1, field2]) // younique 22 | 23 | // This one must stay too. 24 | @@unique([field1, field3]) // there too 25 | } 26 | 27 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformatter/block_attribute_comments_are_preserved.reformatted.prisma: -------------------------------------------------------------------------------- 1 | model MyModel { 2 | // Example Comment 3 | field1 Int // Comment Field 1 4 | field2 Int // Comment Field 2 5 | field3 Int // Comment Field 3 6 | 7 | // This comment should stay here. 8 | @@unique([field1, field2]) // younique 9 | // This one must stay too. 10 | @@unique([field1, field3]) // there too 11 | } 12 | 13 | type YourType { 14 | // Example Comment 15 | field1 Int // Comment Field 1 16 | field2 Int // Comment Field 2 17 | field3 Int // Comment Field 3 18 | 19 | // This comment should stay here. 20 | @@unique([field1, field2]) // younique 21 | // This one must stay too. 22 | @@unique([field1, field3]) // there too 23 | } 24 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformatter/catch_all_in_a_block_must_not_influence_table_layout.prisma: -------------------------------------------------------------------------------- 1 | model Post { 2 | id Int @id 3 | this is an invalid line 4 | anotherField String 5 | } 6 | 7 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformatter/catch_all_in_a_block_must_not_influence_table_layout.reformatted.prisma: -------------------------------------------------------------------------------- 1 | model Post { 2 | id Int @id 3 | this is an invalid line 4 | anotherField String 5 | } 6 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformatter/model_block_attributes_ordering.prisma: -------------------------------------------------------------------------------- 1 | model Person { 2 | firstName String 3 | lastName String 4 | codeName String 5 | yearOfBirth Int 6 | @@map("blog") 7 | @@index([yearOfBirth]) 8 | @@fulltext([firstName, lastName, codeName]) 9 | @@unique([codeName, yearOfBirth]) 10 | @@id([firstName, lastName]) 11 | } 12 | 13 | model Blog { 14 | id Int @default(1) 15 | name String 16 | posts Post[] 17 | @@id([id]) 18 | @@fulltext([name]) 19 | @@index([id, name]) 20 | @@unique([name]) 21 | @@map("blog") 22 | } 23 | 24 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformatter/model_block_attributes_ordering.reformatted.prisma: -------------------------------------------------------------------------------- 1 | model Person { 2 | firstName String 3 | lastName String 4 | codeName String 5 | yearOfBirth Int 6 | 7 | @@id([firstName, lastName]) 8 | @@unique([codeName, yearOfBirth]) 9 | @@index([yearOfBirth]) 10 | @@fulltext([firstName, lastName, codeName]) 11 | @@map("blog") 12 | } 13 | 14 | model Blog { 15 | id Int @default(1) 16 | name String 17 | posts Post[] 18 | 19 | @@id([id]) 20 | @@unique([name]) 21 | @@index([id, name]) 22 | @@fulltext([name]) 23 | @@map("blog") 24 | } 25 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformatter/model_field_attributes_ordering.prisma: -------------------------------------------------------------------------------- 1 | model Post { 2 | id Int @default(autoincrement()) @id 3 | published Boolean @map("_published") @default(false) 4 | author User? @relation(fields: [authorId], references: [id]) 5 | authorId Int? 6 | } 7 | 8 | model User { 9 | megaField DateTime @map("mega_field") @id @default("_megaField") @unique @updatedAt 10 | } 11 | 12 | model Test { 13 | id Int @id @map("_id") @default(1) @updatedAt 14 | blogId Int? @unique @default(1) 15 | } 16 | 17 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformatter/model_field_attributes_ordering.reformatted.prisma: -------------------------------------------------------------------------------- 1 | model Post { 2 | id Int @id @default(autoincrement()) 3 | published Boolean @default(false) @map("_published") 4 | author User? @relation(fields: [authorId], references: [id]) 5 | authorId Int? 6 | } 7 | 8 | model User { 9 | megaField DateTime @id @unique @default("_megaField") @updatedAt @map("mega_field") 10 | } 11 | 12 | model Test { 13 | id Int @id @default(1) @updatedAt @map("_id") 14 | blogId Int? @unique @default(1) 15 | } 16 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformatter/model_single_field.prisma: -------------------------------------------------------------------------------- 1 | model User { 2 | id Int @id 3 | } 4 | 5 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformatter/model_single_field.reformatted.prisma: -------------------------------------------------------------------------------- 1 | model User { 2 | id Int @id 3 | } 4 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformatter/optional_list_fields.prisma: -------------------------------------------------------------------------------- 1 | model Pizza { 2 | id Int @id 3 | toppings String[]? 4 | prices Int[]? @default([3, 6, 9]) 5 | } 6 | 7 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformatter/optional_list_fields.reformatted.prisma: -------------------------------------------------------------------------------- 1 | model Pizza { 2 | id Int @id 3 | toppings String[]? 4 | prices Int[]? @default([3, 6, 9]) 5 | } 6 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformatter/regression_add_relation_attribute_on_field_with_multi_byte_trailing_comment.prisma: -------------------------------------------------------------------------------- 1 | // This is your Prisma schema file, 2 | // learn more about it in the docs: https://pris.ly/d/prisma-schema 3 | 4 | generator client { 5 | provider = "prisma-client-js" 6 | output = "./generated/client" 7 | } 8 | 9 | datasource db { 10 | provider = "sqlserver" 11 | url = "***" 12 | } 13 | 14 | model somemodel { 15 | frownyFaceId String 16 | frownyFace frownyface // 囧 17 | 18 | id Int @id 19 | } 20 | 21 | model frownyface { 22 | somes somemodel[] 23 | } 24 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformatter/regression_add_relation_attribute_on_field_with_multi_byte_trailing_comment.reformatted.prisma: -------------------------------------------------------------------------------- 1 | // This is your Prisma schema file, 2 | // learn more about it in the docs: https://pris.ly/d/prisma-schema 3 | 4 | generator client { 5 | provider = "prisma-client-js" 6 | output = "./generated/client" 7 | } 8 | 9 | datasource db { 10 | provider = "sqlserver" 11 | url = "***" 12 | } 13 | 14 | model somemodel { 15 | frownyFaceId String 16 | frownyFace frownyface @relation(fields: [], references: []) // 囧 17 | 18 | id Int @id 19 | } 20 | 21 | model frownyface { 22 | somes somemodel[] 23 | } 24 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformatter/relations/back_relation_fields_and_attribute_must_be_added_even_when_attribute_is_missing.prisma: -------------------------------------------------------------------------------- 1 | model User { 2 | id Int @id 3 | post Post 4 | } 5 | 6 | model Post { 7 | id Int @id 8 | } 9 | 10 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformatter/relations/back_relation_fields_and_attribute_must_be_added_even_when_attribute_is_missing.reformatted.prisma: -------------------------------------------------------------------------------- 1 | model User { 2 | id Int @id 3 | post Post @relation(fields: [postId], references: [id]) 4 | postId Int 5 | } 6 | 7 | model Post { 8 | id Int @id 9 | User User[] 10 | } 11 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformatter/relations/back_relation_fields_must_be_added.prisma: -------------------------------------------------------------------------------- 1 | model Blog { 2 | id Int @id 3 | posts Post[] 4 | } 5 | 6 | model Post { 7 | id Int @id 8 | } 9 | 10 | model Post2 { 11 | id Int @id 12 | blogId Int 13 | Blog Blog @relation(fields: [blogId], references: [id]) 14 | } 15 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformatter/relations/back_relation_fields_must_be_added.reformatted.prisma: -------------------------------------------------------------------------------- 1 | model Blog { 2 | id Int @id 3 | posts Post[] 4 | Post2 Post2[] 5 | } 6 | 7 | model Post { 8 | id Int @id 9 | Blog Blog? @relation(fields: [blogId], references: [id]) 10 | blogId Int? 11 | } 12 | 13 | model Post2 { 14 | id Int @id 15 | blogId Int 16 | Blog Blog @relation(fields: [blogId], references: [id]) 17 | } 18 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformatter/relations/forward_relation_fields_must_be_added.prisma: -------------------------------------------------------------------------------- 1 | model PostableEntity { 2 | id String @id 3 | } 4 | 5 | model Post { 6 | id String @id 7 | postableEntities PostableEntity[] 8 | } 9 | 10 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformatter/relations/forward_relation_fields_must_be_added.reformatted.prisma: -------------------------------------------------------------------------------- 1 | model PostableEntity { 2 | id String @id 3 | Post Post? @relation(fields: [postId], references: [id]) 4 | postId String? 5 | } 6 | 7 | model Post { 8 | id String @id 9 | postableEntities PostableEntity[] 10 | } 11 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformatter/relations/native_types_in_missing_relation_fields.prisma: -------------------------------------------------------------------------------- 1 | datasource pg { 2 | provider = "postgres" 3 | url = "postgres://meowmeowmeowmeowmeow" 4 | } 5 | 6 | model Blog { 7 | id Int @id @pg.SmallInt 8 | posts Post[] 9 | } 10 | 11 | model Post { 12 | id Int @id @pg.SmallInt 13 | } 14 | 15 | model Post2 { 16 | id Int @id @pg.SmallInt 17 | blogId Int @pg.SmallInt 18 | Blog Blog @relation(fields: [blogId], references: [id]) 19 | } 20 | 21 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformatter/relations/native_types_in_missing_relation_fields.reformatted.prisma: -------------------------------------------------------------------------------- 1 | datasource pg { 2 | provider = "postgres" 3 | url = "postgres://meowmeowmeowmeowmeow" 4 | } 5 | 6 | model Blog { 7 | id Int @id @pg.SmallInt 8 | posts Post[] 9 | Post2 Post2[] 10 | } 11 | 12 | model Post { 13 | id Int @id @pg.SmallInt 14 | Blog Blog? @relation(fields: [blogId], references: [id]) 15 | blogId Int? @pg.SmallInt 16 | } 17 | 18 | model Post2 { 19 | id Int @id @pg.SmallInt 20 | blogId Int @pg.SmallInt 21 | Blog Blog @relation(fields: [blogId], references: [id]) 22 | } 23 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformatter/trailing_comments_allowed_in_configuration_blocks.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "postgres" // "mysql" | "sqlite" ... 3 | url = env("TEST_POSTGRES_URI") 4 | relationMode = "prisma" // = on or set to "foreignKeys" to turn off emulation 5 | } 6 | 7 | generator js { 8 | provider = "prisma-client-js" // optional 9 | previewFeatures = ["referentialIntegrity"] // [] 10 | } 11 | 12 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformatter/trailing_comments_allowed_in_configuration_blocks.reformatted.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "postgres" // "mysql" | "sqlite" ... 3 | url = env("TEST_POSTGRES_URI") 4 | relationMode = "prisma" // = on or set to "foreignKeys" to turn off emulation 5 | } 6 | 7 | generator js { 8 | provider = "prisma-client-js" // optional 9 | previewFeatures = ["referentialIntegrity"] // [] 10 | } 11 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformatter/type_aliases.prisma: -------------------------------------------------------------------------------- 1 | generator client { 2 | provider = "prisma-client-js" 3 | } 4 | 5 | datasource db { 6 | provider = "mongodb" 7 | url = env("TEST_DB_URL") 8 | } 9 | 10 | type MongoID = String @id @default(dbgenerated()) @map("_id") @db.ObjectId 11 | 12 | model User { 13 | id MongoID 14 | email String @unique 15 | } 16 | 17 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/reformatter/type_aliases.reformatted.prisma: -------------------------------------------------------------------------------- 1 | generator client { 2 | provider = "prisma-client-js" 3 | } 4 | 5 | datasource db { 6 | provider = "mongodb" 7 | url = env("TEST_DB_URL") 8 | } 9 | 10 | type MongoID = String @id @default(dbgenerated()) @map("_id") @db.ObjectId 11 | model User { 12 | id MongoID 13 | email String @unique 14 | } 15 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/types/mod.rs: -------------------------------------------------------------------------------- 1 | mod cockroachdb_native_types; 2 | mod composite_types; 3 | mod mongo_native_types; 4 | mod mssql_native_types; 5 | mod mysql_native_types; 6 | mod negative; 7 | mod positive; 8 | mod postgres_native_types; 9 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/index/indexes_on_relation_fields_must_error.prisma: -------------------------------------------------------------------------------- 1 | model User { 2 | id Int @id 3 | identificationId Int 4 | 5 | identification Identification @relation(fields: [identificationId], references:[id]) 6 | 7 | @@index([identification]) 8 | } 9 | 10 | model Identification { 11 | id Int @id 12 | } 13 | 14 | 15 | // error: Error validating model "User": The index definition refers to the relation fields identification. Index definitions must reference only scalar fields. Did you mean `@@index([identificationId])`? 16 | // --> schema.prisma:7 17 | //  |  18 | //  6 |  19 | //  7 |  @@index([identification]) 20 | //  |  21 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/index/missing_index_warning/mongodb.prisma: -------------------------------------------------------------------------------- 1 | // no missing relation index validation on mongodb. 2 | 3 | datasource db { 4 | provider = "mongodb" 5 | url = env("TEST_DATABASE_URL") 6 | } 7 | 8 | model SomeUser { 9 | id String @id @map("_id") @default(auto()) @db.ObjectId 10 | posts Post[] 11 | } 12 | 13 | model Post { 14 | id String @id @map("_id") @default(auto()) @db.ObjectId 15 | userId String @db.ObjectId 16 | user SomeUser @relation(fields: [userId], references: [id]) 17 | } 18 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/index/missing_index_warning/relation_mode_foreign_keys.prisma: -------------------------------------------------------------------------------- 1 | // no missing relation index validation on relationMode = "foreignKeys" / no relationMode at all. 2 | 3 | datasource db { 4 | provider = "mysql" 5 | url = env("TEST_DATABASE_URL") 6 | } 7 | 8 | model SomeUser { 9 | id Int @id 10 | posts Post[] 11 | } 12 | 13 | model Post { 14 | id Int @id 15 | userId Int 16 | user SomeUser @relation(fields: [userId], references: [id]) 17 | } 18 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/index/missing_index_warning/relation_mode_prisma/one_field_at_at_unique.prisma: -------------------------------------------------------------------------------- 1 | // no relation index validation warning on relationMode = "prisma" when a referenced field is already in @@unique. 2 | 3 | datasource db { 4 | provider = "mysql" 5 | url = env("TEST_DATABASE_URL") 6 | relationMode = "prisma" 7 | } 8 | 9 | model SomeUser { 10 | id Int @id 11 | profile Profile? 12 | } 13 | 14 | model Profile { 15 | id Int @id 16 | userId Int 17 | user SomeUser? @relation(fields: [userId], references: [id]) 18 | 19 | @@unique([userId]) 20 | } 21 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/index/missing_index_warning/relation_mode_prisma/one_field_at_unique.prisma: -------------------------------------------------------------------------------- 1 | // no relation index validation warning on relationMode = "prisma" when a referenced field is already in @unique. 2 | 3 | datasource db { 4 | provider = "mysql" 5 | url = env("TEST_DATABASE_URL") 6 | relationMode = "prisma" 7 | } 8 | 9 | model SomeUser { 10 | id Int @id 11 | profile Profile? 12 | } 13 | 14 | model Profile { 15 | id Int @id 16 | userId Int @unique 17 | user SomeUser? @relation(fields: [userId], references: [id]) 18 | } 19 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/index/missing_index_warning/relation_mode_prisma/one_field_no_index.prisma: -------------------------------------------------------------------------------- 1 | // add missing relation index validation warning on relationMode = "prisma". 2 | 3 | datasource db { 4 | provider = "mysql" 5 | url = env("TEST_DATABASE_URL") 6 | relationMode = "prisma" 7 | } 8 | 9 | model SomeUser { 10 | id Int @id 11 | posts Post[] 12 | } 13 | 14 | model Post { 15 | id Int @id 16 | userId Int 17 | user SomeUser @relation(fields: [userId], references: [id]) 18 | } 19 | // warning: With `relationMode = "prisma"`, no foreign keys are used, so relation fields will not benefit from the index usually created by the relational database under the hood. This can lead to poor performance when querying these fields. We recommend adding an index manually. Learn more at https://pris.ly/d/relation-mode-prisma-indexes"  20 | // --> schema.prisma:17 21 | //  |  22 | // 16 |  userId Int 23 | // 17 |  user SomeUser @relation(fields: [userId], references: [id]) 24 | //  |  25 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/index/missing_index_warning/relation_mode_prisma/three_fields_index_leftmost.prisma: -------------------------------------------------------------------------------- 1 | // add missing relation index validation warning on relationMode = "prisma". 2 | 3 | datasource db { 4 | provider = "mysql" 5 | url = env("TEST_DATABASE_URL") 6 | relationMode = "prisma" 7 | } 8 | 9 | model SomeUser { 10 | idA Int 11 | idB Int 12 | idC Int 13 | posts Post[] 14 | 15 | @@id([idA, idB, idC]) 16 | } 17 | 18 | model Post { 19 | id Int @id 20 | userIdA Int 21 | userIdB Int 22 | userIdC Int 23 | user SomeUser @relation(fields: [userIdA, userIdB, userIdC], references: [idA, idB, idC]) 24 | 25 | @@index([userIdA, userIdB]) 26 | } 27 | // warning: With `relationMode = "prisma"`, no foreign keys are used, so relation fields will not benefit from the index usually created by the relational database under the hood. This can lead to poor performance when querying these fields. We recommend adding an index manually. Learn more at https://pris.ly/d/relation-mode-prisma-indexes"  28 | // --> schema.prisma:23 29 | //  |  30 | // 22 |  userIdC Int 31 | // 23 |  user SomeUser @relation(fields: [userIdA, userIdB, userIdC], references: [idA, idB, idC]) 32 | //  |  33 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/index/missing_index_warning/relation_mode_prisma/three_fields_index_rightmost.prisma: -------------------------------------------------------------------------------- 1 | // add missing relation index validation warning on relationMode = "prisma". 2 | 3 | datasource db { 4 | provider = "mysql" 5 | url = env("TEST_DATABASE_URL") 6 | relationMode = "prisma" 7 | } 8 | 9 | model SomeUser { 10 | idA Int 11 | idB Int 12 | idC Int 13 | posts Post[] 14 | 15 | @@id([idA, idB, idC]) 16 | } 17 | 18 | model Post { 19 | id Int @id 20 | userIdA Int 21 | userIdB Int 22 | userIdC Int 23 | user SomeUser @relation(fields: [userIdA, userIdB, userIdC], references: [idA, idB, idC]) 24 | 25 | @@index([userIdB, userIdC]) 26 | } 27 | // warning: With `relationMode = "prisma"`, no foreign keys are used, so relation fields will not benefit from the index usually created by the relational database under the hood. This can lead to poor performance when querying these fields. We recommend adding an index manually. Learn more at https://pris.ly/d/relation-mode-prisma-indexes"  28 | // --> schema.prisma:23 29 | //  |  30 | // 22 |  userIdC Int 31 | // 23 |  user SomeUser @relation(fields: [userIdA, userIdB, userIdC], references: [idA, idB, idC]) 32 | //  |  33 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/index/missing_index_warning/relation_mode_prisma/three_fields_mixed_unique.prisma: -------------------------------------------------------------------------------- 1 | // add missing relation index validation warning on relationMode = "prisma". 2 | 3 | datasource db { 4 | provider = "mysql" 5 | url = env("TEST_DATABASE_URL") 6 | relationMode = "prisma" 7 | } 8 | 9 | model SomeUser { 10 | idA Int 11 | idB Int 12 | idC Int 13 | posts Post[] 14 | 15 | @@id([idA, idB, idC]) 16 | } 17 | 18 | model Post { 19 | id Int @id 20 | userIdA Int @unique 21 | userIdB Int 22 | userIdC Int @unique 23 | user SomeUser @relation(fields: [userIdA, userIdB, userIdC], references: [idA, idB, idC]) 24 | 25 | @@unique([userIdA, userIdB]) 26 | } 27 | // warning: With `relationMode = "prisma"`, no foreign keys are used, so relation fields will not benefit from the index usually created by the relational database under the hood. This can lead to poor performance when querying these fields. We recommend adding an index manually. Learn more at https://pris.ly/d/relation-mode-prisma-indexes"  28 | // --> schema.prisma:23 29 | //  |  30 | // 22 |  userIdC Int @unique 31 | // 23 |  user SomeUser @relation(fields: [userIdA, userIdB, userIdC], references: [idA, idB, idC]) 32 | //  |  33 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/index/missing_index_warning/relation_mode_prisma/three_fields_no_index.prisma: -------------------------------------------------------------------------------- 1 | // add missing relation index validation warning on relationMode = "prisma". 2 | 3 | datasource db { 4 | provider = "mysql" 5 | url = env("TEST_DATABASE_URL") 6 | relationMode = "prisma" 7 | } 8 | 9 | model SomeUser { 10 | idA Int 11 | idB Int 12 | idC Int 13 | posts Post[] 14 | 15 | @@id([idA, idB, idC]) 16 | } 17 | 18 | model Post { 19 | id Int @id 20 | userIdA Int 21 | userIdB Int 22 | userIdC Int 23 | user SomeUser @relation(fields: [userIdA, userIdB, userIdC], references: [idA, idB, idC]) 24 | } 25 | // warning: With `relationMode = "prisma"`, no foreign keys are used, so relation fields will not benefit from the index usually created by the relational database under the hood. This can lead to poor performance when querying these fields. We recommend adding an index manually. Learn more at https://pris.ly/d/relation-mode-prisma-indexes"  26 | // --> schema.prisma:23 27 | //  |  28 | // 22 |  userIdC Int 29 | // 23 |  user SomeUser @relation(fields: [userIdA, userIdB, userIdC], references: [idA, idB, idC]) 30 | //  |  31 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/index/mysql_missing_length.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "mysql" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model User { 7 | id Int @id 8 | firstName String @unique @test.Text 9 | 10 | @@index([firstName]) 11 | } 12 | 13 | // error: Native type `Text` cannot be unique in MySQL. Please use the `length` argument to the field in the index definition to allow this. 14 | // --> schema.prisma:8 15 | //  |  16 | //  7 |  id Int @id 17 | //  8 |  firstName String @unique @test.Text 18 | //  |  19 | // error: You cannot define an index on fields with native type `Text` of MySQL. Please use the `length` argument to the field in the index definition to allow this. 20 | // --> schema.prisma:10 21 | //  |  22 | //  9 |  23 | // 10 |  @@index([firstName]) 24 | //  |  25 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/index/sql_server_disallows_compound_unique_length_prefix.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "sqlserver" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | a String 8 | b String 9 | @@unique([a(length: 10), b(length: 30)]) 10 | } 11 | // error: Error parsing attribute "@@unique": The length argument is not supported in an index definition with the current connector 12 | // --> schema.prisma:9 13 | //  |  14 | //  8 |  b String 15 | //  9 |  @@unique([a(length: 10), b(length: 30)]) 16 | //  |  17 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/index/sql_server_disallows_index_length_prefix.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "sqlserver" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id 8 | a String 9 | 10 | @@index([a(length: 10)]) 11 | } 12 | // error: Error parsing attribute "@@index": The length argument is not supported in an index definition with the current connector 13 | // --> schema.prisma:10 14 | //  |  15 | //  9 |  16 | // 10 |  @@index([a(length: 10)]) 17 | //  |  18 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/index/sqlite_disallows_unique_length_prefix.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "sqlite" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id String @unique(length: 30) 8 | } 9 | 10 | // error: Error parsing attribute "@unique": The length argument is not supported in an index definition with the current connector 11 | // --> schema.prisma:7 12 | //  |  13 | //  6 | model A { 14 | //  7 |  id String @unique(length: 30) 15 | //  |  16 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/index/sqlserver_disallows_unique_length_prefix.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "sqlserver" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id String @unique(length: 30) @test.VarChar(255) 8 | } 9 | 10 | // error: Error parsing attribute "@unique": The length argument is not supported in an index definition with the current connector 11 | // --> schema.prisma:7 12 | //  |  13 | //  6 | model A { 14 | //  7 |  id String @unique(length: 30) @test.VarChar(255) 15 | //  |  16 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/index/string_field_names.prisma: -------------------------------------------------------------------------------- 1 | model User { 2 | id Int @id 3 | firstName String 4 | lastName String 5 | 6 | @@index(["firstName", "lastName"]) 7 | } 8 | 9 | // error: Expected a constant literal value, but received string value `"firstName"`. 10 | // --> schema.prisma:6 11 | //  |  12 | //  5 |  13 | //  6 |  @@index(["firstName", "lastName"]) 14 | //  |  15 | // error: Expected a constant literal value, but received string value `"lastName"`. 16 | // --> schema.prisma:6 17 | //  |  18 | //  5 |  19 | //  6 |  @@index(["firstName", "lastName"]) 20 | //  |  21 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/index/unique_sort_order_as_string.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model Post { 7 | title String @db.VarChar(300) 8 | slug String @unique(sort: "Desc", length: 42) @db.VarChar(3000) 9 | 10 | @@unique([title(length: 100, sort: "Desc")]) 11 | } 12 | 13 | // error: Expected a constant value, but received string value `"Desc"`. 14 | // --> schema.prisma:8 15 | //  |  16 | //  7 |  title String @db.VarChar(300) 17 | //  8 |  slug String @unique(sort: "Desc", length: 42) @db.VarChar(3000) 18 | //  |  19 | // error: Expected a constant value, but received string value `"Desc"`. 20 | // --> schema.prisma:10 21 | //  |  22 | //  9 |  23 | // 10 |  @@unique([title(length: 100, sort: "Desc")]) 24 | //  |  25 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/index/unknown_field.prisma: -------------------------------------------------------------------------------- 1 | model User { 2 | id Int @id 3 | 4 | @@index([foo,bar]) 5 | } 6 | 7 | 8 | // error: Error validating model "User": The index definition refers to the unknown fields: foo, bar. 9 | // --> schema.prisma:4 10 | //  |  11 | //  3 |  12 | //  4 |  @@index([foo,bar]) 13 | //  |  14 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/index_clustering/clustered_compound_unique_on_sqlite.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "sqlite" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id @map("_id") 8 | a Int 9 | b Int 10 | 11 | @@unique([a, b], clustered: true) 12 | } 13 | 14 | 15 | // error: Error parsing attribute "@@unique": Defining clustering is not supported in the current connector. 16 | // --> schema.prisma:11 17 | //  |  18 | // 10 |  19 | // 11 |  @@unique([a, b], clustered: true) 20 | //  |  21 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/index_clustering/id_and_index_clustering_together_not_allowed.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "sqlserver" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id 8 | a Int 9 | 10 | @@index([a], clustered: true) 11 | } 12 | 13 | // error: Error parsing attribute "@id": A model can only hold one clustered index or id. 14 | // --> schema.prisma:7 15 | //  |  16 | //  6 | model A { 17 | //  7 |  id Int @id 18 | //  |  19 | // error: Error parsing attribute "@@index": A model can only hold one clustered index or key. 20 | // --> schema.prisma:10 21 | //  |  22 | //  9 |  23 | // 10 |  @@index([a], clustered: true) 24 | //  |  25 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/index_clustering/id_and_unique_clustering_together_not_allowed.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "sqlserver" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id 8 | a Int 9 | 10 | @@unique([a], clustered: true) 11 | } 12 | 13 | // error: Error parsing attribute "@id": A model can only hold one clustered index or id. 14 | // --> schema.prisma:7 15 | //  |  16 | //  6 | model A { 17 | //  7 |  id Int @id 18 | //  |  19 | // error: Error parsing attribute "@@unique": A model can only hold one clustered index or key. 20 | // --> schema.prisma:10 21 | //  |  22 | //  9 |  23 | // 10 |  @@unique([a], clustered: true) 24 | //  |  25 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/index_clustering/non_boolean_index_clustering.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "sqlserver" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id(clustered: meow) 8 | } 9 | 10 | 11 | // error: Expected a boolean value, but received literal value `meow`. 12 | // --> schema.prisma:7 13 | //  |  14 | //  6 | model A { 15 | //  7 |  id Int @id(clustered: meow) 16 | //  |  17 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/index_clustering/non_clustered_compound_id_sqlite.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "sqlite" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | left Int 8 | right Int 9 | 10 | @@id([left, right], clustered: false) 11 | } 12 | 13 | 14 | // error: Error parsing attribute "@@id": Defining clustering is not supported in the current connector. 15 | // --> schema.prisma:10 16 | //  |  17 | //  9 |  18 | // 10 |  @@id([left, right], clustered: false) 19 | //  |  20 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/index_clustering/non_clustered_id_sqlite.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "sqlite" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id(clustered: false) @map("_id") 8 | } 9 | 10 | // error: Error parsing attribute "@id": Defining clustering is not supported in the current connector. 11 | // --> schema.prisma:7 12 | //  |  13 | //  6 | model A { 14 | //  7 |  id Int @id(clustered: false) @map("_id") 15 | //  |  16 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/index_clustering/on_mysql.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "mysql" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id @map("_id") 8 | a Int 9 | 10 | @@index([a], clustered: true) 11 | } 12 | 13 | // error: Error parsing attribute "@@index": Defining clustering is not supported in the current connector. 14 | // --> schema.prisma:10 15 | //  |  16 | //  9 |  17 | // 10 |  @@index([a], clustered: true) 18 | //  |  19 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/index_clustering/on_postgres.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id @map("_id") 8 | a Int 9 | 10 | @@index([a], clustered: true) 11 | } 12 | 13 | // error: Error parsing attribute "@@index": Defining clustering is not supported in the current connector. 14 | // --> schema.prisma:10 15 | //  |  16 | //  9 |  17 | // 10 |  @@index([a], clustered: true) 18 | //  |  19 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/map/duplicate_models_with_map_on_both_sides.prisma: -------------------------------------------------------------------------------- 1 | datasource mydb { 2 | provider = "sqlite" 3 | url = env("TEST_DB_URL") 4 | } 5 | 6 | model Dog { 7 | id Int @id 8 | 9 | @@map("pets") 10 | } 11 | 12 | model Cat { 13 | id Int @id 14 | 15 | @@map("pets") 16 | } 17 | 18 | // error: The model with database name "pets" could not be defined because another model or view with this name exists: "Dog" 19 | // --> schema.prisma:15 20 | //  |  21 | // 14 |  22 | // 15 |  @@map("pets") 23 | //  |  24 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/map/map_must_error_for_relation_fields.prisma: -------------------------------------------------------------------------------- 1 | model User { 2 | id Int @id 3 | fooId Int 4 | relationField Foo @relation(fields: [fooId], references: [id]) @map("custom_name") 5 | } 6 | 7 | model Foo { 8 | id Int @id 9 | } 10 | 11 | // error: Error parsing attribute "@map": The attribute `@map` cannot be used on relation fields. 12 | // --> schema.prisma:4 13 | //  |  14 | //  3 |  fooId Int 15 | //  4 |  relationField Foo @relation(fields: [fooId], references: [id]) @map("custom_name") 16 | //  |  17 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/map/mongodb_field_map_cannot_contain_periods.prisma: -------------------------------------------------------------------------------- 1 | datasource mydb { 2 | provider = "mongodb" 3 | url = env("TEST_DB_URL") 4 | } 5 | 6 | model Foo { 7 | id Int @id @map("_id") 8 | field String @map("field.schwield") 9 | } 10 | 11 | // error: Error parsing attribute "@map": The field name cannot contain a `.` character 12 | // --> schema.prisma:8 13 | //  |  14 | //  7 |  id Int @id @map("_id") 15 | //  8 |  field String @map("field.schwield") 16 | //  |  17 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/map/mongodb_field_map_cannot_start_with_dollar_sign.prisma: -------------------------------------------------------------------------------- 1 | datasource mydb { 2 | provider = "mongodb" 3 | url = env("TEST_DB_URL") 4 | } 5 | 6 | model Foo { 7 | id Int @id @map("_id") 8 | field String @map("$field") 9 | } 10 | 11 | // error: Error parsing attribute "@map": The field name cannot start with a `$` character 12 | // --> schema.prisma:8 13 | //  |  14 | //  7 |  id Int @id @map("_id") 15 | //  8 |  field String @map("$field") 16 | //  |  17 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/nanoid/require_int_argument.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "mysql" 3 | url = "does_not_matter" 4 | } 5 | 6 | model Category { 7 | id String @id @default(nanoid("asdf")) 8 | } 9 | // error: Error parsing attribute "@default": `nanoid()` takes a single Int argument. 10 | // --> schema.prisma:7 11 | //  |  12 | //  6 | model Category { 13 | //  7 |  id String @id @default(nanoid("asdf")) 14 | //  |  15 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/nanoid/require_minimum_value.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "mysql" 3 | url = "does_not_matter" 4 | } 5 | 6 | model Category { 7 | id String @id @default(nanoid(1)) 8 | } 9 | // error: Error parsing attribute "@default": `nanoid()` takes either no argument, or a single integer argument >= 2. 10 | // --> schema.prisma:7 11 | //  |  12 | //  6 | model Category { 13 | //  7 |  id String @id @default(nanoid(1)) 14 | //  |  15 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/nanoid/require_string_column.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "mysql" 3 | url = "does_not_matter" 4 | } 5 | 6 | model Category { 7 | id Int @id @default(nanoid(1)) 8 | } 9 | // error: Error parsing attribute "@default": The function `nanoid()` cannot be used on fields of type `Int`. 10 | // --> schema.prisma:7 11 | //  |  12 | //  6 | model Category { 13 | //  7 |  id Int @id @default(nanoid(1)) 14 | //  |  15 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/nanoid/string_column_with_length_valid.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "mysql" 3 | url = "does_not_matter" 4 | } 5 | 6 | model Category { 7 | id String @id @default(nanoid(7)) 8 | } 9 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/nanoid/string_column_with_no_argument_valid.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "mysql" 3 | url = "does_not_matter" 4 | } 5 | 6 | model Category { 7 | id String @id @default(nanoid()) 8 | } 9 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/relation_mode/referential_integrity_attr_is_deprecated.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "sqlite" 3 | url = "sqlite" 4 | referentialIntegrity = "foreignKeys" 5 | } 6 | // warning: The `referentialIntegrity` attribute is deprecated. Please use `relationMode` instead. Learn more at https://pris.ly/d/relation-mode 7 | // --> schema.prisma:4 8 | //  |  9 | //  3 |  url = "sqlite" 10 | //  4 |  referentialIntegrity = "foreignKeys" 11 | //  5 | } 12 | //  |  13 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/relation_mode/relation_mode_and_referential_integrity_cannot_cooccur.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "sqlite" 3 | url = "sqlite" 4 | relationMode = "prisma" 5 | referentialIntegrity = "foreignKeys" 6 | } 7 | // warning: The `referentialIntegrity` attribute is deprecated. Please use `relationMode` instead. Learn more at https://pris.ly/d/relation-mode 8 | // --> schema.prisma:5 9 | //  |  10 | //  4 |  relationMode = "prisma" 11 | //  5 |  referentialIntegrity = "foreignKeys" 12 | //  6 | } 13 | //  |  14 | // error: The `referentialIntegrity` and `relationMode` attributes cannot be used together. Please use only `relationMode` instead. 15 | // --> schema.prisma:5 16 | //  |  17 | //  4 |  relationMode = "prisma" 18 | //  5 |  referentialIntegrity = "foreignKeys" 19 | //  6 | } 20 | //  |  21 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/schema/bad_schema_attribute.prisma: -------------------------------------------------------------------------------- 1 | datasource testds { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | schemas = ["public"] 5 | } 6 | 7 | generator js { 8 | provider = "prisma-client-js" 9 | previewFeatures = ["multiSchema"] 10 | } 11 | 12 | model Test { 13 | id Int @id 14 | @@schema 15 | } 16 | 17 | enum Language { 18 | English 19 | Spanish 20 | 21 | @@schema 22 | } 23 | 24 | model Test2 { 25 | id Int @id 26 | @@schema(101) 27 | } 28 | 29 | 30 | // error: Argument "map" is missing. 31 | // --> schema.prisma:14 32 | //  |  33 | // 13 |  id Int @id 34 | // 14 |  @@schema 35 | //  |  36 | // error: Argument "map" is missing. 37 | // --> schema.prisma:21 38 | //  |  39 | // 20 |  40 | // 21 |  @@schema 41 | //  |  42 | // error: Expected a string value, but received numeric value `101`. 43 | // --> schema.prisma:26 44 | //  |  45 | // 25 |  id Int @id 46 | // 26 |  @@schema(101) 47 | //  |  48 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/schema/enums_in_different_schemas_with_same_mapped_name.prisma: -------------------------------------------------------------------------------- 1 | generator client { 2 | provider = "prisma-client-js" 3 | previewFeatures = ["multiSchema"] 4 | } 5 | 6 | datasource db { 7 | provider = "postgresql" 8 | url = env("TEST_DATABASE_URL") 9 | schemas = ["base", "transactional"] 10 | } 11 | 12 | enum Color { 13 | RED 14 | GREEN 15 | BLUE 16 | 17 | @@map("attribute") 18 | @@schema("base") 19 | } 20 | 21 | enum Size { 22 | SMALL 23 | MEDIUM 24 | LARGE 25 | VENTI 26 | 27 | @@map("attribute") 28 | @@schema("transactional") 29 | } 30 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/schema/enums_in_same_schema_with_same_mapped_name.prisma: -------------------------------------------------------------------------------- 1 | generator client { 2 | provider = "prisma-client-js" 3 | previewFeatures = ["multiSchema"] 4 | } 5 | 6 | datasource db { 7 | provider = "postgresql" 8 | url = env("TEST_DATABASE_URL") 9 | schemas = ["base", "transactional"] 10 | } 11 | 12 | enum Color { 13 | RED 14 | GREEN 15 | BLUE 16 | 17 | @@map("attribute") 18 | @@schema("transactional") 19 | } 20 | 21 | enum Size { 22 | SMALL 23 | MEDIUM 24 | LARGE 25 | VENTI 26 | 27 | @@map("attribute") 28 | @@schema("transactional") 29 | } 30 | 31 | // error: An enum with the same database name is already defined. 32 | // --> schema.prisma:21 33 | //  |  34 | // 20 |  35 | // 21 | enum Size { 36 | // 22 |  SMALL 37 | // 23 |  MEDIUM 38 | // 24 |  LARGE 39 | // 25 |  VENTI 40 | // 26 |  41 | // 27 |  @@map("attribute") 42 | // 28 |  @@schema("transactional") 43 | // 29 | } 44 | //  |  45 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/schema/missing_schema_annotations.prisma: -------------------------------------------------------------------------------- 1 | // This is _not_ valid: once @@schema is specified once, it has to be 2 | // specified for every model and enum. 3 | 4 | datasource testds { 5 | provider = "postgresql" 6 | url = env("TEST_DATABASE_URL") 7 | schemas = ["public", "security", "users"] 8 | } 9 | 10 | generator js { 11 | provider = "prisma-client-js" 12 | previewFeatures = ["multiSchema"] 13 | } 14 | 15 | model Test { 16 | id Int @id 17 | } 18 | 19 | model Test2 { 20 | id Int @id 21 | @@schema("public") 22 | } 23 | 24 | enum UserType { 25 | Bacteria 26 | Archea 27 | Eukaryote 28 | } 29 | 30 | // error: Error validating model "Test": This model is missing an `@@schema` attribute. 31 | // --> schema.prisma:15 32 | //  |  33 | // 14 |  34 | // 15 | model Test { 35 | // 16 |  id Int @id 36 | // 17 | } 37 | //  |  38 | // error: This enum is missing an `@@schema` attribute. 39 | // --> schema.prisma:24 40 | //  |  41 | // 23 |  42 | // 24 | enum UserType { 43 | // 25 |  Bacteria 44 | // 26 |  Archea 45 | // 27 |  Eukaryote 46 | // 28 | } 47 | //  |  48 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/schema/multiple_schemas_valid.prisma: -------------------------------------------------------------------------------- 1 | datasource testds { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | schemas = ["public", "security", "users"] 5 | } 6 | 7 | generator js { 8 | provider = "prisma-client-js" 9 | previewFeatures = ["multiSchema"] 10 | } 11 | 12 | model Test { 13 | id Int @id 14 | @@schema("users") 15 | } 16 | 17 | model Test2 { 18 | id Int @id 19 | @@schema("public") 20 | } 21 | 22 | model Test3 { 23 | id Int @id 24 | @@schema("security") 25 | } 26 | 27 | enum UserType { 28 | Bacteria 29 | Archea 30 | Eukaryote 31 | 32 | @@schema("users") 33 | } 34 | 35 | model Test4 { 36 | id Int @id 37 | @@schema("public") 38 | } 39 | 40 | model Test5 { 41 | id Int @id 42 | @@schema("security") 43 | } 44 | 45 | 46 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/schema/mysql_enums_do_not_have_a_schema.prisma: -------------------------------------------------------------------------------- 1 | datasource testds { 2 | provider = "mysql" 3 | url = env("TEST_DATABASE_URL") 4 | schemas = ["public", "security", "users"] 5 | } 6 | 7 | generator js { 8 | provider = "prisma-client-js" 9 | previewFeatures = ["multiSchema"] 10 | } 11 | 12 | 13 | enum MyEnum { 14 | ONE 15 | TWO 16 | 17 | @@schema("users") 18 | } 19 | 20 | 21 | 22 | // error: MySQL enums do not belong to a schema. 23 | // --> schema.prisma:17 24 | //  |  25 | // 16 |  26 | // 17 |  @@schema("users") 27 | //  |  28 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/schema/non_existing_schema.prisma: -------------------------------------------------------------------------------- 1 | datasource testds { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | schemas = ["public"] 5 | } 6 | 7 | generator js { 8 | provider = "prisma-client-js" 9 | previewFeatures = ["multiSchema"] 10 | } 11 | 12 | model Test { 13 | id Int @id 14 | 15 | @@schema("nonpublic") 16 | } 17 | 18 | enum Language { 19 | English 20 | Foreign 21 | 22 | @@schema("nonpublic") 23 | } 24 | 25 | 26 | 27 | // error: This schema is not defined in the datasource. Read more on `@@schema` at https://pris.ly/d/multi-schema 28 | // --> schema.prisma:15 29 | //  |  30 | // 14 |  31 | // 15 |  @@schema("nonpublic") 32 | //  |  33 | // error: This schema is not defined in the datasource. Read more on `@@schema` at https://pris.ly/d/multi-schema 34 | // --> schema.prisma:22 35 | //  |  36 | // 21 |  37 | // 22 |  @@schema("nonpublic") 38 | //  |  39 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/schema/on_sqlite.prisma: -------------------------------------------------------------------------------- 1 | datasource testds { 2 | provider = "sqlite" 3 | url = env("TEST_DATABASE_URL") 4 | schemas = ["public", "sphere"] 5 | } 6 | 7 | generator js { 8 | provider = "prisma-client-js" 9 | previewFeatures = ["multiSchema"] 10 | } 11 | 12 | model Test { 13 | id Int @id 14 | 15 | @@schema("public") 16 | } 17 | 18 | 19 | // error: The `schemas` property is not supported on the current connector. 20 | // --> schema.prisma:4 21 | //  |  22 | //  3 |  url = env("TEST_DATABASE_URL") 23 | //  4 |  schemas = ["public", "sphere"] 24 | //  |  25 | // error: @@schema is not supported on the current datasource provider 26 | // --> schema.prisma:15 27 | //  |  28 | // 14 |  29 | // 15 |  @@schema("public") 30 | //  |  31 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/schema/repeated_schema_attribute.prisma: -------------------------------------------------------------------------------- 1 | datasource testds { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | schemas = ["public", "private"] 5 | } 6 | 7 | generator js { 8 | provider = "prisma-client-js" 9 | previewFeatures = ["multiSchema"] 10 | } 11 | 12 | model Test { 13 | id Int @id 14 | @@schema("public") 15 | } 16 | 17 | enum toggle { 18 | on 19 | off 20 | 21 | @@schema("public") 22 | @@schema("private") 23 | } 24 | 25 | 26 | 27 | // error: Attribute "@schema" can only be defined once. 28 | // --> schema.prisma:21 29 | //  |  30 | // 20 |  31 | // 21 |  @@schema("public") 32 | //  |  33 | // error: Attribute "@schema" can only be defined once. 34 | // --> schema.prisma:22 35 | //  |  36 | // 21 |  @@schema("public") 37 | // 22 |  @@schema("private") 38 | //  |  39 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/schema/tables_in_different_schemas_with_same_constraint_names.prisma: -------------------------------------------------------------------------------- 1 | generator client { 2 | provider = "prisma-client-js" 3 | previewFeatures = ["multiSchema"] 4 | } 5 | 6 | datasource db { 7 | provider = "postgresql" 8 | url = env("TEST_DATABASE_URL") 9 | schemas = ["base", "transactional"] 10 | } 11 | 12 | model User { 13 | id String @id @default(cuid()) 14 | email String 15 | posts Post[] 16 | 17 | @@map("some_table") 18 | @@schema("base") 19 | } 20 | 21 | model Post { 22 | id String @id @default(cuid()) 23 | title String 24 | authorId String 25 | author User? @relation(fields: [authorId], references: [id]) 26 | 27 | @@map("some_table") 28 | @@schema("transactional") 29 | } 30 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/schema/tables_in_different_schemas_with_same_mapped_name.prisma: -------------------------------------------------------------------------------- 1 | // issue: https://github.com/prisma/prisma/issues/15009 2 | 3 | generator client { 4 | provider = "prisma-client-js" 5 | previewFeatures = ["multiSchema"] 6 | } 7 | 8 | datasource db { 9 | provider = "postgresql" 10 | url = env("TEST_DATABASE_URL") 11 | schemas = ["base", "transactional"] 12 | } 13 | 14 | model User { 15 | id String @id 16 | email String 17 | posts Post[] 18 | 19 | @@map("some_table") 20 | @@schema("base") 21 | } 22 | 23 | model Post { 24 | title String 25 | authorId String @unique 26 | author User? @relation(fields: [authorId], references: [id]) 27 | 28 | @@map("some_table") 29 | @@schema("transactional") 30 | } 31 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/schema/tables_in_same_schema_with_same_mapped_name.prisma: -------------------------------------------------------------------------------- 1 | datasource mydb { 2 | provider = "sqlserver" 3 | url = env("TEST_DB_URL") 4 | schemas = ["base", "transactional"] 5 | } 6 | 7 | generator client { 8 | provider = "prisma-client-js" 9 | previewFeatures = ["multiSchema"] 10 | } 11 | 12 | 13 | model Dog { 14 | id Int @id 15 | 16 | @@map("pets") 17 | @@schema("base") 18 | } 19 | 20 | model Cat { 21 | id Int @id(map: "cat_pets_pkey") 22 | 23 | @@map("pets") 24 | @@schema("base") 25 | } 26 | 27 | // error: The model with database name "pets" could not be defined because another model or view with this name exists: "Dog" 28 | // --> schema.prisma:23 29 | //  |  30 | // 22 |  31 | // 23 |  @@map("pets") 32 | //  |  33 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/schema/with_single_schema.prisma: -------------------------------------------------------------------------------- 1 | datasource testds { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | schemas = ["public"] 5 | } 6 | 7 | generator js { 8 | provider = "prisma-client-js" 9 | previewFeatures = ["multiSchema"] 10 | } 11 | 12 | model Test { 13 | id Int @id 14 | @@schema("public") 15 | } 16 | 17 | enum Language { 18 | English 19 | Spanish 20 | 21 | @@schema("public") 22 | } 23 | 24 | 25 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/schema/with_single_schema_mysql.prisma: -------------------------------------------------------------------------------- 1 | datasource testds { 2 | provider = "mysql" 3 | url = env("TEST_DATABASE_URL") 4 | schemas = ["public"] 5 | } 6 | 7 | generator js { 8 | provider = "prisma-client-js" 9 | previewFeatures = ["multiSchema"] 10 | } 11 | 12 | model Test { 13 | id Int @id 14 | lang Language 15 | 16 | @@schema("public") 17 | } 18 | 19 | enum Language { 20 | English 21 | Spanish 22 | } 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/schema/with_single_schema_sqlserver.prisma: -------------------------------------------------------------------------------- 1 | datasource testds { 2 | provider = "sqlserver" 3 | url = env("TEST_DATABASE_URL") 4 | schemas = ["public"] 5 | } 6 | 7 | generator js { 8 | provider = "prisma-client-js" 9 | previewFeatures = ["multiSchema"] 10 | } 11 | 12 | model Test { 13 | id Int @id 14 | @@schema("public") 15 | } 16 | 17 | 18 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/attributes/schema/without_preview_feature.prisma: -------------------------------------------------------------------------------- 1 | datasource testds { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model Test { 7 | id Int @id 8 | 9 | @@schema("public") 10 | } 11 | 12 | // error: @@schema is only available with the `multiSchema` preview feature. 13 | // --> schema.prisma:9 14 | //  |  15 | //  8 |  16 | //  9 |  @@schema("public") 17 | //  |  18 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/capabilities/mongodb_does_not_support_autoincrement.prisma: -------------------------------------------------------------------------------- 1 | datasource mydb { 2 | provider = "mongodb" 3 | url = env("TEST_DB_URL") 4 | } 5 | 6 | model User { 7 | id Int @id @default(autoincrement()) @map("_id") 8 | } 9 | 10 | 11 | // error: Error parsing attribute "@default": The `autoincrement()` default value is used with a datasource that does not support it. 12 | // --> schema.prisma:7 13 | //  |  14 | //  6 | model User { 15 | //  7 |  id Int @id @default(autoincrement()) @map("_id") 16 | //  |  17 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/capabilities/mongodb_supports_composite_types.prisma: -------------------------------------------------------------------------------- 1 | datasource mydb { 2 | provider = "mongodb" 3 | url = env("TEST_DB_URL") 4 | } 5 | 6 | 7 | type Address { 8 | street String 9 | } 10 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/cockroachdb/negative_time_precision.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "cockroachdb" 3 | url = env("DATABASE_URL") 4 | } 5 | 6 | model User { 7 | id Int @id 8 | val DateTime @db.Timestamp(-1) 9 | val2 DateTime @db.Time(-1) 10 | } 11 | 12 | // error: Expected a nonnegative integer, but found (-1). 13 | // --> schema.prisma:8 14 | //  |  15 | //  7 |  id Int @id 16 | //  8 |  val DateTime @db.Timestamp(-1) 17 | //  |  18 | // error: Expected a nonnegative integer, but found (-1). 19 | // --> schema.prisma:9 20 | //  |  21 | //  8 |  val DateTime @db.Timestamp(-1) 22 | //  9 |  val2 DateTime @db.Time(-1) 23 | //  |  24 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/composite_types/ignore_field_attribute_is_not_allowed.prisma: -------------------------------------------------------------------------------- 1 | datasource mdb { 2 | provider = "mongodb" 3 | url = env("TESTDBURL") 4 | } 5 | 6 | type A { 7 | name String 8 | c String @ignore 9 | } 10 | 11 | model B { 12 | id Int @id 13 | a A 14 | } 15 | 16 | 17 | 18 | 19 | // error: Attribute not known: "@ignore". 20 | // --> schema.prisma:8 21 | //  |  22 | //  7 |  name String 23 | //  8 |  c String @ignore 24 | //  |  25 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/composite_types/map_field_attribute_is_allowed.prisma: -------------------------------------------------------------------------------- 1 | datasource mdb { 2 | provider = "mongodb" 3 | url = env("TESTDBURL") 4 | } 5 | 6 | type A { 7 | name String @map("alias") 8 | } 9 | 10 | model B { 11 | id Int @id @map("_id") 12 | a A 13 | } 14 | 15 | 16 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/composite_types/relation_field_attribute_not_allowed.prisma: -------------------------------------------------------------------------------- 1 | datasource mdb { 2 | provider = "mongodb" 3 | url = env("TESTDBURL") 4 | } 5 | 6 | type C { 7 | val String 8 | } 9 | 10 | type A { 11 | c C[] @relation("foo") 12 | } 13 | 14 | model B { 15 | id Int @id 16 | a A 17 | } 18 | 19 | 20 | // error: Error validating: Defining `@relation` attribute for a field in a composite type is not allowed. 21 | // --> schema.prisma:11 22 | //  |  23 | // 10 | type A { 24 | // 11 |  c C[] @relation("foo") 25 | // 12 | } 26 | //  |  27 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/composite_types/unique_index_field_clash.prisma: -------------------------------------------------------------------------------- 1 | datasource mdb { 2 | provider = "mongodb" 3 | url = env("TESTDBURL") 4 | } 5 | 6 | type Street { 7 | description String 8 | } 9 | 10 | type Address { 11 | street Street 12 | } 13 | 14 | type Location { 15 | address Address 16 | country String 17 | } 18 | 19 | model A { 20 | id Int @id @map("_id") 21 | name String 22 | my_location Location 23 | name_my_location_address_street_description String? 24 | 25 | @@unique([name, my_location.address.street.description]) 26 | } 27 | 28 | 29 | 30 | 31 | // error: Error validating model "A": The field `name_my_location_address_street_description` clashes with the `@@unique` name. Please resolve the conflict by providing a custom id name: `@@unique([...], name: "custom_name")` 32 | // --> schema.prisma:25 33 | //  |  34 | // 24 |  35 | // 25 |  @@unique([name, my_location.address.street.description]) 36 | //  |  37 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/datasource/duplicates_in_schemas.prisma: -------------------------------------------------------------------------------- 1 | datasource testds { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | schemas = ["one", "two", "two", "three", "three"] 5 | } 6 | 7 | // error: Duplicated schema names are not allowed 8 | // --> schema.prisma:4 9 | //  |  10 | //  3 |  url = env("TEST_DATABASE_URL") 11 | //  4 |  schemas = ["one", "two", "two", "three", "three"] 12 | //  |  13 | // error: Duplicated schema names are not allowed 14 | // --> schema.prisma:4 15 | //  |  16 | //  3 |  url = env("TEST_DATABASE_URL") 17 | //  4 |  schemas = ["one", "two", "two", "three", "three"] 18 | //  |  19 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/datasource/schemas_array_with_non_string_values.prisma: -------------------------------------------------------------------------------- 1 | datasource testds { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | schemas = ["one", 2, ["three"]] 5 | } 6 | 7 | 8 | // error: Expected a string value, but received numeric value `2`. 9 | // --> schema.prisma:4 10 | //  |  11 | //  3 |  url = env("TEST_DATABASE_URL") 12 | //  4 |  schemas = ["one", 2, ["three"]] 13 | //  |  14 | // error: Expected a string value, but received array value `["three"]`. 15 | // --> schema.prisma:4 16 | //  |  17 | //  3 |  url = env("TEST_DATABASE_URL") 18 | //  4 |  schemas = ["one", 2, ["three"]] 19 | //  |  20 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/mysql/set_default_warning.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "mysql" 3 | url = "mysql://" 4 | } 5 | 6 | model A { 7 | id Int @id 8 | bs B[] 9 | } 10 | 11 | model B { 12 | id Int @id 13 | aId Int? @default(3) 14 | a A? @relation(fields: [aId], references: [id], onUpdate: SetDefault, onDelete: SetDefault) 15 | } 16 | // warning: MySQL does not actually support the `SetDefault` referential action, so using it may result in unexpected errors. Read more at https://pris.ly/d/mysql-set-default  17 | // --> schema.prisma:14 18 | //  |  19 | // 13 |  aId Int? @default(3) 20 | // 14 |  a A? @relation(fields: [aId], references: [id], onUpdate: SetDefault, onDelete: SetDefault) 21 | //  |  22 | // warning: MySQL does not actually support the `SetDefault` referential action, so using it may result in unexpected errors. Read more at https://pris.ly/d/mysql-set-default  23 | // --> schema.prisma:14 24 | //  |  25 | // 13 |  aId Int? @default(3) 26 | // 14 |  a A? @relation(fields: [aId], references: [id], onUpdate: SetDefault, onDelete: SetDefault) 27 | //  |  28 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/mysql/set_default_warning_when_relation_mode_foreignkeys.prisma: -------------------------------------------------------------------------------- 1 | generator client { 2 | provider = "prisma-client-js" 3 | } 4 | 5 | datasource db { 6 | provider = "mysql" 7 | url = "mysql://" 8 | relationMode = "foreignKeys" 9 | } 10 | 11 | model A { 12 | id Int @id 13 | bs B[] 14 | } 15 | 16 | model B { 17 | id Int @id 18 | aId Int? @default(3) 19 | a A? @relation(fields: [aId], references: [id], onUpdate: SetDefault, onDelete: SetDefault) 20 | } 21 | // warning: MySQL does not actually support the `SetDefault` referential action, so using it may result in unexpected errors. Read more at https://pris.ly/d/mysql-set-default  22 | // --> schema.prisma:19 23 | //  |  24 | // 18 |  aId Int? @default(3) 25 | // 19 |  a A? @relation(fields: [aId], references: [id], onUpdate: SetDefault, onDelete: SetDefault) 26 | //  |  27 | // warning: MySQL does not actually support the `SetDefault` referential action, so using it may result in unexpected errors. Read more at https://pris.ly/d/mysql-set-default  28 | // --> schema.prisma:19 29 | //  |  30 | // 18 |  aId Int? @default(3) 31 | // 19 |  a A? @relation(fields: [aId], references: [id], onUpdate: SetDefault, onDelete: SetDefault) 32 | //  |  33 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres/negative_time_precision.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "postgresql" 3 | url = env("DATABASE_URL") 4 | } 5 | 6 | model User { 7 | id Int @id 8 | val DateTime @db.Timestamp(-1) 9 | val2 DateTime @db.Time(-1) 10 | } 11 | 12 | // error: Expected a nonnegative integer, but found (-1). 13 | // --> schema.prisma:8 14 | //  |  15 | //  7 |  id Int @id 16 | //  8 |  val DateTime @db.Timestamp(-1) 17 | //  |  18 | // error: Expected a nonnegative integer, but found (-1). 19 | // --> schema.prisma:9 20 | //  |  21 | //  8 |  val DateTime @db.Timestamp(-1) 22 | //  9 |  val2 DateTime @db.Time(-1) 23 | //  |  24 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_extensions/extensions_are_not_numbers.prisma: -------------------------------------------------------------------------------- 1 | generator js { 2 | provider = "prisma-client-js" 3 | previewFeatures = [ "postgresqlExtensions" ] 4 | } 5 | 6 | datasource mypg { 7 | provider = "postgresql" 8 | url = env("TEST_DATABASE_URL") 9 | extensions = [ 1 ] 10 | } 11 | // error: Expected a constant or function value, but received numeric value `1`. 12 | // --> schema.prisma:9 13 | //  |  14 | //  8 |  url = env("TEST_DATABASE_URL") 15 | //  9 |  extensions = [ 1 ] 16 | //  |  17 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_extensions/extensions_are_not_strings.prisma: -------------------------------------------------------------------------------- 1 | generator js { 2 | provider = "prisma-client-js" 3 | previewFeatures = [ "postgresqlExtensions" ] 4 | } 5 | 6 | datasource mypg { 7 | provider = "postgresql" 8 | url = env("TEST_DATABASE_URL") 9 | extensions = [ "postgis" ] 10 | } 11 | // error: Expected a constant or function value, but received string value `"postgis"`. 12 | // --> schema.prisma:9 13 | //  |  14 | //  8 |  url = env("TEST_DATABASE_URL") 15 | //  9 |  extensions = [ "postgis" ] 16 | //  |  17 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_extensions/extensions_do_not_work_on_mongodb.prisma: -------------------------------------------------------------------------------- 1 | generator js { 2 | provider = "prisma-client-js" 3 | previewFeatures = ["postgresqlExtensions"] 4 | } 5 | 6 | datasource mypg { 7 | provider = "mongodb" 8 | url = env("TEST_DATABASE_URL") 9 | extensions = [postgis] 10 | } 11 | // error: Property not known: "extensions". 12 | // --> schema.prisma:9 13 | //  |  14 | //  8 |  url = env("TEST_DATABASE_URL") 15 | //  9 |  extensions = [postgis] 16 | // 10 | } 17 | //  |  18 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_extensions/extensions_do_not_work_on_mysql.prisma: -------------------------------------------------------------------------------- 1 | generator js { 2 | provider = "prisma-client-js" 3 | previewFeatures = ["postgresqlExtensions"] 4 | } 5 | 6 | datasource db { 7 | provider = "mysql" 8 | url = env("TEST_DATABASE_URL") 9 | extensions = [postgis] 10 | } 11 | // error: Property not known: "extensions". 12 | // --> schema.prisma:9 13 | //  |  14 | //  8 |  url = env("TEST_DATABASE_URL") 15 | //  9 |  extensions = [postgis] 16 | // 10 | } 17 | //  |  18 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_extensions/extensions_do_not_work_on_sqlite.prisma: -------------------------------------------------------------------------------- 1 | generator js { 2 | provider = "prisma-client-js" 3 | previewFeatures = ["postgresqlExtensions"] 4 | } 5 | 6 | datasource db { 7 | provider = "sqlite" 8 | url = env("TEST_DATABASE_URL") 9 | extensions = [postgis] 10 | } 11 | // error: Property not known: "extensions". 12 | // --> schema.prisma:9 13 | //  |  14 | //  8 |  url = env("TEST_DATABASE_URL") 15 | //  9 |  extensions = [postgis] 16 | // 10 | } 17 | //  |  18 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_extensions/extensions_do_not_work_on_sqlserver.prisma: -------------------------------------------------------------------------------- 1 | generator js { 2 | provider = "prisma-client-js" 3 | previewFeatures = ["postgresqlExtensions"] 4 | } 5 | 6 | datasource db { 7 | provider = "sqlserver" 8 | url = env("TEST_DATABASE_URL") 9 | extensions = [postgis] 10 | } 11 | // error: Property not known: "extensions". 12 | // --> schema.prisma:9 13 | //  |  14 | //  8 |  url = env("TEST_DATABASE_URL") 15 | //  9 |  extensions = [postgis] 16 | // 10 | } 17 | //  |  18 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_extensions/extensions_require_feature_flag.prisma: -------------------------------------------------------------------------------- 1 | generator js { 2 | provider = "prisma-client-js" 3 | } 4 | 5 | datasource mypg { 6 | provider = "postgresql" 7 | url = env("TEST_DATABASE_URL") 8 | extensions = [ postgis ] 9 | } 10 | // error: The `extensions` property is only available with the `postgresqlExtensions` preview feature. 11 | // --> schema.prisma:8 12 | //  |  13 | //  7 |  url = env("TEST_DATABASE_URL") 14 | //  8 |  extensions = [ postgis ] 15 | //  9 | } 16 | //  |  17 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_extensions/extensions_with_arguments.prisma: -------------------------------------------------------------------------------- 1 | generator js { 2 | provider = "prisma-client-js" 3 | previewFeatures = ["postgresqlExtensions"] 4 | } 5 | 6 | datasource mypg { 7 | provider = "postgresql" 8 | url = env("TEST_DATABASE_URL") 9 | extensions = [uuid_ossp(map: "uuid-ossp", schema: "meow", version: "2.1")] 10 | } 11 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_extensions/extensions_with_duplicate_arguments.prisma: -------------------------------------------------------------------------------- 1 | generator js { 2 | provider = "prisma-client-js" 3 | previewFeatures = ["postgresqlExtensions"] 4 | } 5 | 6 | datasource mypg { 7 | provider = "postgresql" 8 | url = env("TEST_DATABASE_URL") 9 | extensions = [postgis(version: "2.1", version: "1.0")] 10 | } 11 | // error: Error validating: The argument `version` can only be defined once 12 | // --> schema.prisma:9 13 | //  |  14 | //  8 |  url = env("TEST_DATABASE_URL") 15 | //  9 |  extensions = [postgis(version: "2.1", version: "1.0")] 16 | //  |  17 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_extensions/extensions_with_float_arguments.prisma: -------------------------------------------------------------------------------- 1 | generator js { 2 | provider = "prisma-client-js" 3 | previewFeatures = ["postgresqlExtensions"] 4 | } 5 | 6 | datasource mypg { 7 | provider = "postgresql" 8 | url = env("TEST_DATABASE_URL") 9 | extensions = [postgis(version: 2.1)] 10 | } 11 | // error: Expected a string value, but received numeric value `2.1`. 12 | // --> schema.prisma:9 13 | //  |  14 | //  8 |  url = env("TEST_DATABASE_URL") 15 | //  9 |  extensions = [postgis(version: 2.1)] 16 | //  |  17 | // error: Error validating: The `version` argument must be a string literal 18 | // --> schema.prisma:9 19 | //  |  20 | //  8 |  url = env("TEST_DATABASE_URL") 21 | //  9 |  extensions = [postgis(version: 2.1)] 22 | //  |  23 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_extensions/extensions_with_garbage_arguments.prisma: -------------------------------------------------------------------------------- 1 | generator js { 2 | provider = "prisma-client-js" 3 | previewFeatures = ["postgresqlExtensions"] 4 | } 5 | 6 | datasource mypg { 7 | provider = "postgresql" 8 | url = env("TEST_DATABASE_URL") 9 | extensions = [postgis(version: "2.1", foobar: "1.0")] 10 | } 11 | // error: Argument not known: "foobar". 12 | // --> schema.prisma:9 13 | //  |  14 | //  8 |  url = env("TEST_DATABASE_URL") 15 | //  9 |  extensions = [postgis(version: "2.1", foobar: "1.0")] 16 | //  |  17 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_extensions/extensions_with_unnamed_arguments.prisma: -------------------------------------------------------------------------------- 1 | generator js { 2 | provider = "prisma-client-js" 3 | previewFeatures = ["postgresqlExtensions"] 4 | } 5 | 6 | datasource mypg { 7 | provider = "postgresql" 8 | url = env("TEST_DATABASE_URL") 9 | extensions = [postgis("2.1")] 10 | } 11 | // error: Error validating: The argument must have a name 12 | // --> schema.prisma:9 13 | //  |  14 | //  8 |  url = env("TEST_DATABASE_URL") 15 | //  9 |  extensions = [postgis("2.1")] 16 | //  |  17 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_extensions/feature_flag.prisma: -------------------------------------------------------------------------------- 1 | generator js { 2 | provider = "prisma-client-js" 3 | previewFeatures = [ "postgresqlExtensions" ] 4 | } 5 | 6 | datasource mypg { 7 | provider = "postgresql" 8 | url = env("TEST_DATABASE_URL") 9 | } 10 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_extensions/invalid_characters_in_name.prisma: -------------------------------------------------------------------------------- 1 | generator js { 2 | provider = "prisma-client-js" 3 | previewFeatures = ["postgresqlExtensions"] 4 | } 5 | 6 | datasource mypg { 7 | provider = "postgresql" 8 | url = env("TEST_DATABASE_URL") 9 | extensions = [uuid-ossp] 10 | } 11 | // error: Error validating: The character `-` is not allowed in extension names. 12 | // --> schema.prisma:9 13 | //  |  14 | //  8 |  url = env("TEST_DATABASE_URL") 15 | //  9 |  extensions = [uuid-ossp] 16 | //  |  17 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_extensions/simple_single_extension.prisma: -------------------------------------------------------------------------------- 1 | generator js { 2 | provider = "prisma-client-js" 3 | previewFeatures = [ "postgresqlExtensions" ] 4 | } 5 | 6 | datasource mypg { 7 | provider = "postgresql" 8 | url = env("TEST_DATABASE_URL") 9 | extensions = [ postgis ] 10 | } 11 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_extensions/single_extension_does_not_need_an_array.prisma: -------------------------------------------------------------------------------- 1 | generator js { 2 | provider = "prisma-client-js" 3 | previewFeatures = ["postgresqlExtensions"] 4 | } 5 | 6 | datasource mypg { 7 | provider = "postgresql" 8 | url = env("TEST_DATABASE_URL") 9 | extensions = postgis 10 | } 11 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_indexes/brin/bit_minmax_no_native_type.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id 8 | a String 9 | 10 | @@index([a(ops: BitMinMaxOps)], type: Brin) 11 | } 12 | 13 | // error: Error parsing attribute "@@index": The given operator class `BitMinMaxOps` expects the field `a` to define a valid native type. 14 | // --> schema.prisma:10 15 | //  |  16 | //  9 |  17 | // 10 |  @@index([a(ops: BitMinMaxOps)], type: Brin) 18 | //  |  19 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_indexes/brin/bit_minmax_wrong_native_type.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id 8 | a String @test.VarBit 9 | 10 | @@index([a(ops: BitMinMaxOps)], type: Brin) 11 | } 12 | // error: Error parsing attribute "@@index": The given operator class `BitMinMaxOps` does not support native type `VarBit` of field `a`. 13 | // --> schema.prisma:10 14 | //  |  15 | //  9 |  16 | // 10 |  @@index([a(ops: BitMinMaxOps)], type: Brin) 17 | //  |  18 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_indexes/brin/date_bloom_wrong_native_type.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id 8 | a DateTime @test.Time 9 | 10 | @@index([a(ops: DateBloomOps)], type: Brin) 11 | } 12 | // error: Error parsing attribute "@@index": The given operator class `DateBloomOps` does not support native type `Time` of field `a`. 13 | // --> schema.prisma:10 14 | //  |  15 | //  9 |  16 | // 10 |  @@index([a(ops: DateBloomOps)], type: Brin) 17 | //  |  18 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_indexes/brin/date_minmax_wrong_native_type.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id 8 | a DateTime @test.Time 9 | 10 | @@index([a(ops: DateMinMaxOps)], type: Brin) 11 | } 12 | // error: Error parsing attribute "@@index": The given operator class `DateMinMaxOps` does not support native type `Time` of field `a`. 13 | // --> schema.prisma:10 14 | //  |  15 | //  9 |  16 | // 10 |  @@index([a(ops: DateMinMaxOps)], type: Brin) 17 | //  |  18 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_indexes/brin/date_minmaxmulti_wrong_native_type.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id 8 | a DateTime @test.Time 9 | 10 | @@index([a(ops: DateMinMaxMultiOps)], type: Brin) 11 | } 12 | 13 | // error: Error parsing attribute "@@index": The given operator class `DateMinMaxMultiOps` does not support native type `Time` of field `a`. 14 | // --> schema.prisma:10 15 | //  |  16 | //  9 |  17 | // 10 |  @@index([a(ops: DateMinMaxMultiOps)], type: Brin) 18 | //  |  19 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_indexes/brin/on_mysql.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "mysql" 3 | url = env("DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id 8 | a Int 9 | 10 | @@index([a(ops: raw("whatever_ops"))], type: Brin) 11 | } 12 | 13 | // error: Error parsing attribute "@@index": The given index type is not supported with the current connector 14 | // --> schema.prisma:10 15 | //  |  16 | //  9 |  17 | // 10 |  @@index([a(ops: raw("whatever_ops"))], type: Brin) 18 | //  |  19 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_indexes/brin/uuid_bloom_wrong_native_type.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id 8 | a String @test.Text 9 | 10 | @@index([a(ops: UuidBloomOps)], type: Brin) 11 | } 12 | 13 | // error: Error parsing attribute "@@index": The given operator class `UuidBloomOps` does not support native type `Text` of field `a`. 14 | // --> schema.prisma:10 15 | //  |  16 | //  9 |  17 | // 10 |  @@index([a(ops: UuidBloomOps)], type: Brin) 18 | //  |  19 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_indexes/brin/uuid_minmax_wrong_native_type.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id 8 | a String @test.Text 9 | 10 | @@index([a(ops: UuidMinMaxOps)], type: Brin) 11 | } 12 | // error: Error parsing attribute "@@index": The given operator class `UuidMinMaxOps` does not support native type `Text` of field `a`. 13 | // --> schema.prisma:10 14 | //  |  15 | //  9 |  16 | // 10 |  @@index([a(ops: UuidMinMaxOps)], type: Brin) 17 | //  |  18 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_indexes/brin/uuid_minmaxmulti_wrong_native_type.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id 8 | a String @test.Text 9 | 10 | @@index([a(ops: UuidMinMaxMultiOps)], type: Brin) 11 | } 12 | 13 | // error: Error parsing attribute "@@index": The given operator class `BitMinMaxOps` does not support native type `Text` of field `a`. 14 | // --> schema.prisma:10 15 | //  |  16 | //  9 |  17 | // 10 |  @@index([a(ops: UuidMinMaxMultiOps)], type: Brin) 18 | //  |  19 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_indexes/brin/varbit_minmax_no_native_type.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id 8 | a String 9 | 10 | @@index([a(ops: VarBitMinMaxOps)], type: Brin) 11 | } 12 | // error: Error parsing attribute "@@index": The given operator class `VarBitMinMaxOps` expects the field `a` to define a valid native type. 13 | // --> schema.prisma:10 14 | //  |  15 | //  9 |  16 | // 10 |  @@index([a(ops: VarBitMinMaxOps)], type: Brin) 17 | //  |  18 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_indexes/brin/varbit_minmax_wrong_native_type.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id 8 | a String @test.Bit 9 | 10 | @@index([a(ops: VarBitMinMaxOps)], type: Brin) 11 | } 12 | 13 | // error: Error parsing attribute "@@index": The given operator class `VarBitMinMaxOps` does not support native type `Bit` of field `a`. 14 | // --> schema.prisma:10 15 | //  |  16 | //  9 |  17 | // 10 |  @@index([a(ops: VarBitMinMaxOps)], type: Brin) 18 | //  |  19 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_indexes/gin/array_ops_default_ops.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id 8 | a String[] @test.Uuid 9 | 10 | @@index([a], type: Gin) 11 | } 12 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_indexes/gin/array_ops_invalid_index_type.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id 8 | a Int[] 9 | 10 | @@index([a(ops: ArrayOps)], type: Gist) 11 | } 12 | 13 | 14 | // error: Error parsing attribute "@@index": The given operator class `ArrayOps` is not supported with the `Gist` index type. 15 | // --> schema.prisma:10 16 | //  |  17 | //  9 |  18 | // 10 |  @@index([a(ops: ArrayOps)], type: Gist) 19 | //  |  20 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_indexes/gin/on_mysql.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "mysql" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id 8 | a Json 9 | 10 | @@index([a(ops: JsonbOps)], type: Gin) 11 | } 12 | 13 | // error: Error parsing attribute "@@index": The given index type is not supported with the current connector 14 | // --> schema.prisma:10 15 | //  |  16 | //  9 |  17 | // 10 |  @@index([a(ops: JsonbOps)], type: Gin) 18 | //  |  19 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_indexes/spgist/inet_ops_with_wrong_index_type.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id 8 | a String @test.Inet 9 | 10 | @@index([a(ops: InetOps)], type: Gin) 11 | } 12 | 13 | 14 | // error: Error parsing attribute "@@index": The given operator class `InetOps` is not supported with the `Gin` index type. 15 | // --> schema.prisma:10 16 | //  |  17 | //  9 |  18 | // 10 |  @@index([a(ops: InetOps)], type: Gin) 19 | //  |  20 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_indexes/spgist/inet_ops_with_wrong_prisma_type.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id 8 | a Int 9 | 10 | @@index([a(ops: InetOps)], type: SpGist) 11 | } 12 | 13 | 14 | // error: Error parsing attribute "@@index": The given operator class `InetOps` expects the field `a` to define a valid native type. 15 | // --> schema.prisma:10 16 | //  |  17 | //  9 |  18 | // 10 |  @@index([a(ops: InetOps)], type: SpGist) 19 | //  |  20 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_indexes/spgist/no_ops_weird_type.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id 8 | a Int 9 | 10 | @@index([a], type: SpGist) 11 | } 12 | 13 | 14 | // error: Error parsing attribute "@@index": The SpGist index type does not support the type of the field `a`. 15 | // --> schema.prisma:10 16 | //  |  17 | //  9 |  18 | // 10 |  @@index([a], type: SpGist) 19 | //  |  20 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_indexes/spgist/on_mysql.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "mysql" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id 8 | a Unsupported("polygon") 9 | 10 | @@index([a(ops: raw("poly_ops"))], type: SpGist) 11 | } 12 | 13 | 14 | // error: Error parsing attribute "@@index": The given index type is not supported with the current connector 15 | // --> schema.prisma:10 16 | //  |  17 | //  9 |  18 | // 10 |  @@index([a(ops: raw("poly_ops"))], type: SpGist) 19 | //  |  20 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_indexes/spgist/only_single_column_allowed.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id 8 | a String @test.Inet 9 | b String @test.Inet 10 | 11 | @@index([a, b], type: SpGist) 12 | } 13 | 14 | 15 | // error: Error parsing attribute "@@index": SpGist does not support multi-column indices. 16 | // --> schema.prisma:11 17 | //  |  18 | // 10 |  19 | // 11 |  @@index([a, b], type: SpGist) 20 | //  |  21 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_indexes/spgist/text_ops_with_wrong_index_type.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id 8 | a String @test.Text 9 | 10 | @@index([a(ops: TextOps)], type: Gist) 11 | } 12 | 13 | 14 | // error: Error parsing attribute "@@index": The given operator class `TextOps` is not supported with the `Gist` index type. 15 | // --> schema.prisma:10 16 | //  |  17 | //  9 |  18 | // 10 |  @@index([a(ops: TextOps)], type: Gist) 19 | //  |  20 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/postgres_indexes/spgist/text_ops_with_wrong_prisma_type.prisma: -------------------------------------------------------------------------------- 1 | datasource test { 2 | provider = "postgresql" 3 | url = env("TEST_DATABASE_URL") 4 | } 5 | 6 | model A { 7 | id Int @id 8 | a Int 9 | 10 | @@index([a(ops: TextOps)], type: SpGist) 11 | } 12 | 13 | // error: Error parsing attribute "@@index": The given operator class `TextOps` points to the field `a` that is not of String type. 14 | // --> schema.prisma:10 15 | //  |  16 | //  9 |  17 | // 10 |  @@index([a(ops: TextOps)], type: SpGist) 18 | //  |  19 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/relations/mongodb/relation_same_native_type_1.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "mongodb" 3 | url = "mongodb://" 4 | } 5 | 6 | model Parent { 7 | id String @id @default(auto()) @map("_id") @db.ObjectId 8 | 9 | childId String @unique 10 | child Child? @relation(fields: [childId], references: [parentId]) 11 | } 12 | 13 | model Child { 14 | id String @id @default(auto()) @map("_id") @db.ObjectId 15 | parentId String @unique @db.ObjectId 16 | parent Parent? 17 | } 18 | // warning: Warning validating field `child` in model `Parent`: Field Parent.childId and Child.parentId must have the same native type for MongoDB to join those collections correctly. Consider either removing Child.parentId's native type attribute or adding '@db.ObjectId' to Parent.childId. Beware that this will become an error in the future. 19 | // --> schema.prisma:9 20 | //  |  21 | //  8 |  22 | //  9 |  childId String @unique 23 | // 10 |  child Child? @relation(fields: [childId], references: [parentId]) 24 | //  |  25 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/relations/mongodb/relation_same_native_type_2.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "mongodb" 3 | url = "mongodb://" 4 | } 5 | 6 | model Parent { 7 | id String @id @default(auto()) @map("_id") @db.ObjectId 8 | 9 | childId String @unique @db.ObjectId 10 | child Child? @relation(fields: [childId], references: [parentId]) 11 | } 12 | 13 | model Child { 14 | id String @id @default(auto()) @map("_id") @db.ObjectId 15 | parentId String @unique 16 | parent Parent? 17 | } 18 | 19 | // warning: Warning validating field `child` in model `Parent`: Field Parent.childId and Child.parentId must have the same native type for MongoDB to join those collections correctly. Consider either removing Parent.childId's native type attribute or adding '@db.ObjectId' to Child.parentId. Beware that this will become an error in the future. 20 | // --> schema.prisma:9 21 | //  |  22 | //  8 |  23 | //  9 |  childId String @unique @db.ObjectId 24 | // 10 |  child Child? @relation(fields: [childId], references: [parentId]) 25 | //  |  26 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/relations/mongodb/relation_same_native_type_3.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "mongodb" 3 | url = "mongodb://" 4 | } 5 | 6 | model Parent { 7 | id String @id @default(auto()) @map("_id") @db.ObjectId 8 | 9 | childId String @unique @db.ObjectId 10 | child Child? @relation(fields: [childId], references: [parentId]) 11 | } 12 | 13 | model Child { 14 | id String @id @default(auto()) @map("_id") @db.ObjectId 15 | parentId String @unique @db.String 16 | parent Parent? 17 | } 18 | 19 | // warning: Warning validating field `child` in model `Parent`: Field Parent.childId and Child.parentId must have the same native type for MongoDB to join those collections correctly. Consider updating those fields to either use '@db.ObjectId' or '@db.String'. Beware that this will become an error in the future. 20 | // --> schema.prisma:9 21 | //  |  22 | //  8 |  23 | //  9 |  childId String @unique @db.ObjectId 24 | // 10 |  child Child? @relation(fields: [childId], references: [parentId]) 25 | //  |  26 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/relations/relation_field_with_ignored_or_unspported_fields_does_not_need_ignore.prisma: -------------------------------------------------------------------------------- 1 | model Cat { 2 | id Int @id 3 | boxId Int? 4 | fits Boolean @ignore 5 | box Box? @relation(fields: [boxId, fits], references: [id, fits]) 6 | } 7 | 8 | model GuineaPig { 9 | id Int @id 10 | boxId Int? 11 | material Unsupported("material") 12 | box Box? @relation(fields: [boxId, material], references: [id, material]) 13 | } 14 | 15 | model Box { 16 | id Int @id 17 | fits Boolean 18 | material Unsupported("material") 19 | cats Cat[] 20 | pig GuineaPig[] 21 | 22 | @@unique([id, material]) 23 | @@unique([id, fits]) 24 | } 25 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/relations/set_null_is_not_valid_on_required_fields.prisma: -------------------------------------------------------------------------------- 1 | model SomeUser { 2 | id Int @id 3 | profile Profile? 4 | } 5 | 6 | model Profile { 7 | id Int @id 8 | user SomeUser? @relation(fields: [user_id], references: [id], onUpdate: SetNull, onDelete: SetNull) 9 | user_id Int @unique 10 | } 11 | // error: Error parsing attribute "@relation": The `onDelete` referential action of a relation must not be set to `SetNull` when a referenced field is required. 12 | // Either choose another referential action, or make the referenced fields optional. 13 | //  14 | // --> schema.prisma:8 15 | //  |  16 | //  7 |  id Int @id 17 | //  8 |  user SomeUser? @relation(fields: [user_id], references: [id], onUpdate: SetNull, onDelete: SetNull) 18 | //  9 |  user_id Int @unique 19 | //  |  20 | // error: Error parsing attribute "@relation": The `onUpdate` referential action of a relation must not be set to `SetNull` when a referenced field is required. 21 | // Either choose another referential action, or make the referenced fields optional. 22 | //  23 | // --> schema.prisma:8 24 | //  |  25 | //  7 |  id Int @id 26 | //  8 |  user SomeUser? @relation(fields: [user_id], references: [id], onUpdate: SetNull, onDelete: SetNull) 27 | //  9 |  user_id Int @unique 28 | //  |  29 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/relations/set_null_still_valid_on_optional_fields.prisma: -------------------------------------------------------------------------------- 1 | model SomeUser { 2 | id Int @id 3 | profile Profile? 4 | } 5 | 6 | model Profile { 7 | id Int @id 8 | user SomeUser? @relation(fields: [user_id], references: [id], onUpdate: SetNull, onDelete: SetNull) 9 | user_id Int? @unique 10 | } -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/views/basic_view.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "postgresql" 3 | url = env("DATABASE_URL") 4 | } 5 | 6 | generator js { 7 | provider = "prisma-client-js" 8 | previewFeatures = ["views"] 9 | } 10 | 11 | view Mountain { 12 | id Int @unique 13 | val String 14 | } 15 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/views/duplicate_field.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "postgresql" 3 | url = env("DATABASE_URL") 4 | } 5 | 6 | generator js { 7 | provider = "prisma-client-js" 8 | previewFeatures = ["views"] 9 | } 10 | 11 | view Mountain { 12 | id Int @unique 13 | id Int 14 | } 15 | 16 | // error: Field "id" is already defined on view "Mountain". 17 | // --> schema.prisma:13 18 | //  |  19 | // 12 |  id Int @unique 20 | // 13 |  id Int 21 | //  |  22 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/views/duplicate_view_model_names.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "postgresql" 3 | url = env("DATABASE_URL") 4 | } 5 | 6 | generator js { 7 | provider = "prisma-client-js" 8 | previewFeatures = ["views"] 9 | } 10 | 11 | view Mountain { 12 | id Int @unique 13 | val String 14 | } 15 | 16 | model Mountain { 17 | id Int @unique 18 | val String 19 | } 20 | // error: The model "Mountain" cannot be defined because a view with that name already exists. 21 | // --> schema.prisma:16 22 | //  |  23 | // 15 |  24 | // 16 | model Mountain { 25 | //  |  26 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/views/duplicate_view_model_names_2.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "postgresql" 3 | url = env("DATABASE_URL") 4 | } 5 | 6 | generator js { 7 | provider = "prisma-client-js" 8 | previewFeatures = ["views"] 9 | } 10 | 11 | model Mountain { 12 | id Int @unique 13 | val String 14 | } 15 | 16 | view Mountain { 17 | id Int @unique 18 | val String 19 | } 20 | 21 | // error: The view "Mountain" cannot be defined because a model with that name already exists. 22 | // --> schema.prisma:16 23 | //  |  24 | // 15 |  25 | // 16 | view Mountain { 26 | //  |  27 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/views/duplicate_view_names.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "postgresql" 3 | url = env("DATABASE_URL") 4 | } 5 | 6 | generator js { 7 | provider = "prisma-client-js" 8 | previewFeatures = ["views"] 9 | } 10 | 11 | view Mountain { 12 | id Int @unique 13 | val String 14 | } 15 | 16 | view Mountain { 17 | id Int @unique 18 | val String 19 | } 20 | // error: The view "Mountain" cannot be defined because a view with that name already exists. 21 | // --> schema.prisma:16 22 | //  |  23 | // 15 |  24 | // 16 | view Mountain { 25 | //  |  26 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/views/field_name_starts_with_number.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "postgresql" 3 | url = env("DATABASE_URL") 4 | } 5 | 6 | view foo { 7 | 1id Int @unique 8 | } 9 | 10 | // error: Error validating: The name of a field must not start with a number. 11 | // --> schema.prisma:7 12 | //  |  13 | //  6 | view foo { 14 | //  7 |  1id Int @unique 15 | //  |  16 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/views/garbage_field_definition.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "postgresql" 3 | url = env("DATABASE_URL") 4 | } 5 | 6 | generator js { 7 | provider = "prisma-client-js" 8 | previewFeatures = ["views"] 9 | } 10 | 11 | view Mountain { 12 | id Int @unique 13 | val 14 | } 15 | // error: Error validating view "Mountain": This field declaration is invalid. It is either missing a name or a type. 16 | // --> schema.prisma:13 17 | //  |  18 | // 12 |  id Int @unique 19 | // 13 |  val 20 | // 14 | } 21 | //  |  22 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/views/multi_schema.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "postgresql" 3 | url = env("DATABASE_URL") 4 | schemas = ["A", "B"] 5 | } 6 | 7 | generator js { 8 | provider = "prisma-client-js" 9 | previewFeatures = ["views", "multiSchema"] 10 | } 11 | 12 | model A { 13 | id Int @id 14 | 15 | @@schema("B") 16 | } 17 | 18 | view Mountain { 19 | id Int @unique 20 | 21 | @@schema("A") 22 | } 23 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/views/multi_schema_no_schema_declaration.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "postgresql" 3 | url = env("DATABASE_URL") 4 | schemas = ["A", "B"] 5 | } 6 | 7 | generator js { 8 | provider = "prisma-client-js" 9 | previewFeatures = ["views", "multiSchema"] 10 | } 11 | 12 | model A { 13 | id Int @id 14 | 15 | @@schema("B") 16 | } 17 | 18 | view Mountain { 19 | id Int @unique 20 | } 21 | // error: Error validating view "Mountain": This view is missing an `@@schema` attribute. 22 | // --> schema.prisma:18 23 | //  |  24 | // 17 |  25 | // 18 | view Mountain { 26 | // 19 |  id Int @unique 27 | // 20 | } 28 | //  |  29 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/views/name_starts_with_number.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "postgresql" 3 | url = env("DATABASE_URL") 4 | } 5 | 6 | view 1foo { 7 | id Int @unique 8 | } 9 | 10 | // error: Error validating: The name of a view must not start with a number. 11 | // --> schema.prisma:6 12 | //  |  13 | //  5 |  14 | //  6 | view 1foo { 15 | //  |  16 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/views/no_preview_feature.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "postgresql" 3 | url = env("DATABASE_URL") 4 | } 5 | 6 | view Mountain { 7 | id Int @unique 8 | val String 9 | } 10 | 11 | 12 | // error: Error validating: View definitions are only available with the `views` preview feature. 13 | // --> schema.prisma:6 14 | //  |  15 | //  5 |  16 | //  6 | view Mountain { 17 | //  7 |  id Int @unique 18 | //  8 |  val String 19 | //  9 | } 20 | //  |  21 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/views/no_unique.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "postgresql" 3 | url = env("DATABASE_URL") 4 | } 5 | 6 | generator js { 7 | provider = "prisma-client-js" 8 | previewFeatures = ["views"] 9 | } 10 | 11 | view Mountain { 12 | id Int 13 | } 14 | // error: Error validating view "Mountain": Each view must have at least one unique criteria that has only required fields. Either mark a single field with `@id`, `@unique` or add a multi field criterion with `@@id([])` or `@@unique([])` to the view. 15 | // --> schema.prisma:11 16 | //  |  17 | // 10 |  18 | // 11 | view Mountain { 19 | // 12 |  id Int 20 | // 13 | } 21 | //  |  22 | -------------------------------------------------------------------------------- /crates/ast/psl/tests/validation/views/reserved_name.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "postgresql" 3 | url = env("DATABASE_URL") 4 | } 5 | 6 | view Cat { 7 | id Int @unique 8 | id Int 9 | } 10 | 11 | // error: Field "id" is already defined on view "Cat". 12 | // --> schema.prisma:8 13 | //  |  14 | //  7 |  id Int @unique 15 | //  8 |  id Int 16 | //  |  17 | -------------------------------------------------------------------------------- /crates/ast/psl_core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "psl_core" 4 | version = "0.1.0" 5 | 6 | [dependencies] 7 | diagnostics = { path = "../diagnostics" } 8 | parser_database = { path = "../parser_database" } 9 | prisma_value = { path = "../../libs/prisma_value" } 10 | schema_ast = { path = "../schema_ast" } 11 | 12 | serde_json = { version = "1", features = ["float_roundtrip", "preserve_order"] } 13 | serde = { version = "1", features = ["derive"] } 14 | 15 | bigdecimal = "0.3" 16 | chrono = { version = "0.4.6", default_features = false } 17 | itertools = "0.10" 18 | once_cell = "1.3.1" 19 | regex = "1.3.7" 20 | enumflags2 = "0.7" 21 | indoc = "1" 22 | 23 | # For the connector API. 24 | lsp-types = "0.91.1" 25 | url = "2.2.1" 26 | -------------------------------------------------------------------------------- /crates/ast/psl_core/README.md: -------------------------------------------------------------------------------- 1 | # PSL core 2 | 3 | This crate is the entry point for the core of the PSL implementation. It 4 | exposes the `Connector` trait and relies on its implementors, but it is itself 5 | decoupled from any specific connector. 6 | -------------------------------------------------------------------------------- /crates/ast/psl_core/src/common.rs: -------------------------------------------------------------------------------- 1 | //! This module contains shared constants and logic that can be used by engines. 2 | 3 | mod preview_features; 4 | 5 | pub use self::preview_features::{FeatureMap, PreviewFeature, PreviewFeatures, ALL_PREVIEW_FEATURES}; 6 | -------------------------------------------------------------------------------- /crates/ast/psl_core/src/configuration.rs: -------------------------------------------------------------------------------- 1 | mod configuration_struct; 2 | mod datasource; 3 | mod env_vars; 4 | mod generator; 5 | 6 | pub use configuration_struct::*; 7 | pub use datasource::*; 8 | pub use env_vars::*; 9 | pub use generator::*; 10 | -------------------------------------------------------------------------------- /crates/ast/psl_core/src/configuration/generator.rs: -------------------------------------------------------------------------------- 1 | use crate::{configuration::StringFromEnvVar, PreviewFeature}; 2 | use enumflags2::BitFlags; 3 | use serde::{ser::SerializeSeq, Serialize, Serializer}; 4 | use std::collections::HashMap; 5 | 6 | #[derive(Debug, Serialize, Clone)] 7 | #[serde(rename_all = "camelCase")] 8 | pub struct Generator { 9 | pub name: String, 10 | pub provider: StringFromEnvVar, 11 | pub output: Option, 12 | pub config: HashMap, 13 | 14 | #[serde(default)] 15 | pub binary_targets: Vec, 16 | 17 | #[serde(default, serialize_with = "mcf_preview_features")] 18 | pub preview_features: Option>, 19 | 20 | #[serde(skip_serializing_if = "Option::is_none")] 21 | pub documentation: Option, 22 | } 23 | 24 | pub fn mcf_preview_features(feats: &Option>, s: S) -> Result 25 | where 26 | S: Serializer, 27 | { 28 | let feats = feats.unwrap_or_default(); 29 | let mut seq = s.serialize_seq(Some(feats.len()))?; 30 | for feat in feats.iter() { 31 | seq.serialize_element(&feat)?; 32 | } 33 | seq.end() 34 | } 35 | -------------------------------------------------------------------------------- /crates/ast/psl_core/src/datamodel_connector/filters.rs: -------------------------------------------------------------------------------- 1 | //! Client filter types. 2 | 3 | #![deny(missing_docs)] 4 | 5 | use enumflags2::*; 6 | 7 | macro_rules! filters { 8 | ($(#[$docs:meta] $variant:ident,)*) => { 9 | /// Available filters for a given `String` scalar field. 10 | #[bitflags] 11 | #[derive(Debug, Clone, Copy)] 12 | #[repr(u8)] 13 | pub enum StringFilter { 14 | $(#[$docs] $variant),* 15 | } 16 | 17 | impl StringFilter { 18 | /// The property name of the filter in the client API. 19 | pub fn name(&self) -> String { 20 | let pascal_cased_name = match self { 21 | $(StringFilter::$variant => stringify!($variant)),* 22 | }; 23 | let mut out = pascal_cased_name.to_owned(); 24 | out[0..1].make_ascii_lowercase(); // camel case it 25 | out 26 | } 27 | } 28 | }; 29 | } 30 | 31 | filters! { 32 | /// String contains another string. 33 | Contains, 34 | /// String starts with another string. 35 | StartsWith, 36 | /// String ends with another string. 37 | EndsWith, 38 | } 39 | -------------------------------------------------------------------------------- /crates/ast/psl_core/src/datamodel_connector/relation_mode.rs: -------------------------------------------------------------------------------- 1 | use crate::datamodel_connector::ReferentialAction; 2 | use enumflags2::{bitflags, BitFlags}; 3 | use std::fmt; 4 | 5 | /// Defines the part of the stack where referential actions are handled. 6 | #[bitflags] 7 | #[repr(u8)] 8 | #[derive(Debug, Copy, Clone, PartialEq)] 9 | pub enum RelationMode { 10 | /// Enforced in the database. Needs support from the underlying database 11 | /// server. 12 | ForeignKeys, 13 | /// Enforced in Prisma. Slower, but for databases that do not support 14 | /// foreign keys. 15 | Prisma, 16 | } 17 | 18 | impl RelationMode { 19 | pub fn allowed_emulated_referential_actions_default() -> BitFlags { 20 | use ReferentialAction::*; 21 | 22 | Restrict | SetNull | NoAction | Cascade 23 | } 24 | 25 | pub fn is_prisma(&self) -> bool { 26 | matches!(self, Self::Prisma) 27 | } 28 | 29 | /// True, if integrity is in database foreign keys 30 | pub fn uses_foreign_keys(&self) -> bool { 31 | matches!(self, Self::ForeignKeys) 32 | } 33 | } 34 | 35 | impl Default for RelationMode { 36 | fn default() -> Self { 37 | Self::ForeignKeys 38 | } 39 | } 40 | 41 | impl fmt::Display for RelationMode { 42 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 43 | match self { 44 | RelationMode::ForeignKeys => write!(f, "foreignKeys"), 45 | RelationMode::Prisma => write!(f, "prisma"), 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /crates/ast/psl_core/src/mcf.rs: -------------------------------------------------------------------------------- 1 | mod generator; 2 | mod source; 3 | 4 | pub use generator::*; 5 | pub use source::*; 6 | 7 | use serde::Serialize; 8 | 9 | pub fn config_to_mcf_json_value(mcf: &crate::Configuration) -> serde_json::Value { 10 | serde_json::to_value(&model_to_serializable(mcf)).expect("Failed to render JSON.") 11 | } 12 | 13 | #[derive(Debug, Serialize)] 14 | #[serde(rename_all = "camelCase")] 15 | pub struct SerializeableMcf { 16 | generators: serde_json::Value, 17 | datasources: serde_json::Value, 18 | warnings: Vec, 19 | } 20 | 21 | fn model_to_serializable(config: &crate::Configuration) -> SerializeableMcf { 22 | SerializeableMcf { 23 | generators: generator::generators_to_json_value(&config.generators), 24 | datasources: source::render_sources_to_json_value(&config.datasources), 25 | warnings: config.warnings.iter().map(|f| f.message().to_owned()).collect(), 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /crates/ast/psl_core/src/mcf/generator.rs: -------------------------------------------------------------------------------- 1 | use crate::configuration::Generator; 2 | 3 | pub fn generators_to_json_value(generators: &[Generator]) -> serde_json::Value { 4 | serde_json::to_value(generators).expect("Failed to render JSON.") 5 | } 6 | 7 | pub fn generators_to_json(generators: &[Generator]) -> String { 8 | serde_json::to_string_pretty(generators).expect("Failed to render JSON.") 9 | } 10 | -------------------------------------------------------------------------------- /crates/ast/psl_core/src/validate.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod datasource_loader; 2 | pub(crate) mod generator_loader; 3 | mod validation_pipeline; 4 | 5 | pub(crate) use validation_pipeline::validate; 6 | -------------------------------------------------------------------------------- /crates/ast/psl_core/src/validate/validation_pipeline/context.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | datamodel_connector::{Connector, RelationMode}, 3 | Datasource, PreviewFeature, 4 | }; 5 | use diagnostics::{DatamodelError, DatamodelWarning, Diagnostics}; 6 | use enumflags2::BitFlags; 7 | 8 | /// The validation context. The lifetime parameter is _not_ the AST lifetime, but the subtype of 9 | /// all relevant lifetimes. No data escapes for validations, so the context only need to be valid 10 | /// for the duration of validations. 11 | pub(crate) struct Context<'a> { 12 | pub(super) db: &'a parser_database::ParserDatabase, 13 | pub(super) datasource: Option<&'a Datasource>, 14 | pub(super) preview_features: BitFlags, 15 | pub(super) connector: &'static dyn Connector, 16 | /// Relation mode is a pure function of the datasource, but since there are defaults, 17 | /// it's more consistent to resolve it once, here. 18 | pub(super) relation_mode: RelationMode, 19 | pub(super) diagnostics: &'a mut Diagnostics, 20 | } 21 | 22 | impl Context<'_> { 23 | /// Pure convenience method. Forwards to Diagnostics::push_error(). 24 | pub(super) fn push_error(&mut self, error: DatamodelError) { 25 | self.diagnostics.push_error(error); 26 | } 27 | 28 | /// Pure convenience method. Forwards to Diagnostics::push_warning(). 29 | pub(super) fn push_warning(&mut self, warning: DatamodelWarning) { 30 | self.diagnostics.push_warning(warning); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /crates/ast/psl_core/src/validate/validation_pipeline/validations/database_name.rs: -------------------------------------------------------------------------------- 1 | use crate::{ast, validate::validation_pipeline::context::Context}; 2 | 3 | pub(super) fn validate_db_name( 4 | model_name: &str, 5 | attribute: &ast::Attribute, 6 | db_name: Option<&str>, 7 | ctx: &mut Context<'_>, 8 | // How many @ in the error message? 9 | double_at: bool, 10 | ) { 11 | if let Some(err) = crate::datamodel_connector::constraint_names::ConstraintNames::is_db_name_too_long( 12 | attribute.span, 13 | model_name, 14 | db_name, 15 | &attribute.name.name, 16 | ctx.connector, 17 | double_at, 18 | ) { 19 | ctx.push_error(err); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /crates/ast/psl_core/src/validate/validation_pipeline/validations/datasource.rs: -------------------------------------------------------------------------------- 1 | use diagnostics::DatamodelError; 2 | 3 | use crate::{validate::validation_pipeline::context::Context, Datasource}; 4 | 5 | pub(super) fn schemas_property_without_preview_feature(datasource: &Datasource, ctx: &mut Context<'_>) { 6 | if ctx.preview_features.contains(crate::PreviewFeature::MultiSchema) { 7 | return; 8 | } 9 | 10 | if let Some(span) = datasource.schemas_span { 11 | ctx.push_error(DatamodelError::new_static( 12 | "The `schemas` property is only availably with the `multiSchema` preview feature.", 13 | span, 14 | )) 15 | } 16 | } 17 | 18 | pub(super) fn schemas_property_with_no_connector_support(datasource: &Datasource, ctx: &mut Context<'_>) { 19 | if !ctx.preview_features.contains(crate::PreviewFeature::MultiSchema) { 20 | return; 21 | } 22 | 23 | if ctx 24 | .connector 25 | .has_capability(crate::datamodel_connector::ConnectorCapability::MultiSchema) 26 | { 27 | return; 28 | } 29 | 30 | if let Some(span) = datasource.schemas_span { 31 | ctx.push_error(DatamodelError::new_static( 32 | "The `schemas` property is not supported on the current connector.", 33 | span, 34 | )) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /crates/ast/psl_core/src/validate/validation_pipeline/validations/relations/many_to_many.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod embedded; 2 | pub(crate) mod implicit; 3 | -------------------------------------------------------------------------------- /crates/ast/psl_core/src/validate/validation_pipeline/validations/views.rs: -------------------------------------------------------------------------------- 1 | use diagnostics::DatamodelError; 2 | use parser_database::{ast::WithSpan, walkers::ModelWalker}; 3 | 4 | use crate::validate::validation_pipeline::context::Context; 5 | 6 | pub(crate) fn view_definition_without_preview_flag(model: ModelWalker<'_>, ctx: &mut Context<'_>) { 7 | if ctx.preview_features.contains(crate::PreviewFeature::Views) { 8 | return; 9 | } 10 | 11 | if !model.ast_model().is_view() { 12 | return; 13 | } 14 | 15 | ctx.push_error(DatamodelError::new_validation_error( 16 | "View definitions are only available with the `views` preview feature.", 17 | model.ast_model().span(), 18 | )); 19 | } 20 | -------------------------------------------------------------------------------- /crates/ast/schema_ast/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "schema_ast" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | diagnostics = { path = "../diagnostics" } 8 | 9 | pest = "2.1.3" 10 | pest_derive = "2.1.0" -------------------------------------------------------------------------------- /crates/ast/schema_ast/src/ast/comment.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Clone, PartialEq)] 2 | pub(crate) struct Comment { 3 | pub text: String, 4 | } 5 | -------------------------------------------------------------------------------- /crates/ast/schema_ast/src/ast/config.rs: -------------------------------------------------------------------------------- 1 | use crate::ast::{Expression, Identifier, Span, WithSpan}; 2 | 3 | /// A named property in a config block. 4 | /// 5 | /// ```ignore 6 | /// datasource db { 7 | /// url = env("URL") 8 | /// ^^^^^^^^^^^^^^^^ 9 | /// } 10 | /// ``` 11 | #[derive(Debug, Clone)] 12 | pub struct ConfigBlockProperty { 13 | /// The property name. 14 | /// 15 | /// ```ignore 16 | /// datasource db { 17 | /// url = env("URL") 18 | /// ^^^ 19 | /// } 20 | /// ``` 21 | pub name: Identifier, 22 | /// The property value. 23 | /// 24 | /// ```ignore 25 | /// datasource db { 26 | /// url = env("URL") 27 | /// ^^^^^^^^^^ 28 | /// } 29 | /// ``` 30 | pub value: Expression, 31 | /// The node span. 32 | pub span: Span, 33 | } 34 | 35 | impl WithSpan for ConfigBlockProperty { 36 | fn span(&self) -> Span { 37 | self.span 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /crates/ast/schema_ast/src/ast/generator_config.rs: -------------------------------------------------------------------------------- 1 | use super::{Comment, Identifier, Span, WithDocumentation, WithIdentifier, WithSpan}; 2 | use crate::ast::config::ConfigBlockProperty; 3 | 4 | /// A Generator block declaration. 5 | #[derive(Debug, Clone)] 6 | pub struct GeneratorConfig { 7 | /// Name of this generator. 8 | pub name: Identifier, 9 | /// Top-level configuration properties for this generator. 10 | pub properties: Vec, 11 | /// The comments for this generator block. 12 | pub(crate) documentation: Option, 13 | /// The location of this generator block in the text representation. 14 | pub span: Span, 15 | } 16 | 17 | impl WithIdentifier for GeneratorConfig { 18 | fn identifier(&self) -> &Identifier { 19 | &self.name 20 | } 21 | } 22 | 23 | impl WithSpan for GeneratorConfig { 24 | fn span(&self) -> Span { 25 | self.span 26 | } 27 | } 28 | 29 | impl WithDocumentation for GeneratorConfig { 30 | fn documentation(&self) -> Option<&str> { 31 | self.documentation.as_ref().map(|doc| doc.text.as_str()) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /crates/ast/schema_ast/src/ast/identifier.rs: -------------------------------------------------------------------------------- 1 | use super::{Span, WithSpan}; 2 | 3 | /// An identifier. 4 | #[derive(Debug, Clone, PartialEq)] 5 | pub struct Identifier { 6 | /// The identifier contents. 7 | pub name: String, 8 | /// The span of the AST node. 9 | pub span: Span, 10 | } 11 | 12 | impl WithSpan for Identifier { 13 | fn span(&self) -> Span { 14 | self.span 15 | } 16 | } 17 | 18 | impl From> for Identifier { 19 | fn from(pair: pest::iterators::Pair<'_, T>) -> Self { 20 | Identifier { 21 | name: pair.as_str().to_owned(), 22 | span: pair.as_span().into(), 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /crates/ast/schema_ast/src/ast/indentation_type.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | /// Defines the indentation of a PSL block. 4 | #[derive(Debug, Clone, Copy, PartialEq)] 5 | pub enum IndentationType { 6 | /// Uses a tab character. 7 | Tabs, 8 | /// Uses the given amount of spaces. 9 | Spaces(usize), 10 | } 11 | 12 | impl Default for IndentationType { 13 | /// Prisma defaults to the JavaScript default of two spaces. 14 | fn default() -> Self { 15 | Self::Spaces(2) 16 | } 17 | } 18 | 19 | impl fmt::Display for IndentationType { 20 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 21 | match self { 22 | Self::Tabs => f.write_str("\t"), 23 | Self::Spaces(num) => { 24 | for _ in 0..*num { 25 | f.write_str(" ")?; 26 | } 27 | 28 | Ok(()) 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /crates/ast/schema_ast/src/ast/newline_type.rs: -------------------------------------------------------------------------------- 1 | use std::fmt; 2 | 3 | /// Defines the newline type of a PSL block. 4 | #[derive(Default, Debug, Clone, Copy, PartialEq)] 5 | pub enum NewlineType { 6 | /// `\\n` 7 | #[default] 8 | Unix, 9 | /// `\\r\\n` 10 | Windows, 11 | } 12 | 13 | impl fmt::Display for NewlineType { 14 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 15 | f.write_str(self.as_ref()) 16 | } 17 | } 18 | 19 | impl AsRef for NewlineType { 20 | fn as_ref(&self) -> &str { 21 | match self { 22 | NewlineType::Unix => "\n", 23 | NewlineType::Windows => "\r\n", 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /crates/ast/schema_ast/src/ast/source_config.rs: -------------------------------------------------------------------------------- 1 | use super::{Comment, ConfigBlockProperty, Identifier, Span, WithDocumentation, WithIdentifier, WithSpan}; 2 | 3 | /// A source block declaration. 4 | #[derive(Debug, Clone)] 5 | pub struct SourceConfig { 6 | /// Name of this source. 7 | pub name: Identifier, 8 | /// Top-level configuration properties for this source. 9 | pub properties: Vec, 10 | /// The comments for this source block. 11 | pub(crate) documentation: Option, 12 | /// The location of this source block in the text representation. 13 | pub span: Span, 14 | } 15 | 16 | impl WithIdentifier for SourceConfig { 17 | fn identifier(&self) -> &Identifier { 18 | &self.name 19 | } 20 | } 21 | 22 | impl WithSpan for SourceConfig { 23 | fn span(&self) -> Span { 24 | self.span 25 | } 26 | } 27 | 28 | impl WithDocumentation for SourceConfig { 29 | fn documentation(&self) -> Option<&str> { 30 | self.documentation.as_ref().map(|doc| doc.text.as_str()) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /crates/ast/schema_ast/src/ast/traits.rs: -------------------------------------------------------------------------------- 1 | use super::{Attribute, Identifier, Span}; 2 | 3 | /// An AST node with a span. 4 | pub trait WithSpan { 5 | /// The span of the node. 6 | fn span(&self) -> Span; 7 | } 8 | 9 | /// An AST node with a name (from the identifier). 10 | pub trait WithName { 11 | /// The name of the item. 12 | fn name(&self) -> &str; 13 | } 14 | 15 | /// An AST node with an identifier. 16 | pub trait WithIdentifier { 17 | /// The identifier. 18 | fn identifier(&self) -> &Identifier; 19 | } 20 | 21 | /// An AST node with attributes. 22 | pub trait WithAttributes { 23 | /// The attributes. 24 | fn attributes(&self) -> &[Attribute]; 25 | } 26 | 27 | /// An AST node with documentation. 28 | pub trait WithDocumentation { 29 | /// The documentation string, if defined. 30 | fn documentation(&self) -> Option<&str>; 31 | } 32 | 33 | /// An AST node with a name. 34 | impl WithName for T 35 | where 36 | T: WithIdentifier, 37 | { 38 | /// The name token of the node. 39 | fn name(&self) -> &str { 40 | &self.identifier().name 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /crates/ast/schema_ast/src/parser.rs: -------------------------------------------------------------------------------- 1 | mod helpers; 2 | mod parse_arguments; 3 | mod parse_attribute; 4 | mod parse_comments; 5 | mod parse_composite_type; 6 | mod parse_enum; 7 | mod parse_expression; 8 | mod parse_field; 9 | mod parse_model; 10 | mod parse_schema; 11 | mod parse_source_and_generator; 12 | mod parse_types; 13 | mod parse_view; 14 | 15 | pub use parse_schema::parse_schema; 16 | 17 | // The derive is placed here because it generates the `Rule` enum which is used in all parsing functions. 18 | // It is more convenient if this enum is directly available here. 19 | #[derive(pest_derive::Parser)] 20 | #[grammar = "parser/datamodel.pest"] 21 | pub(crate) struct PrismaDatamodelParser; -------------------------------------------------------------------------------- /crates/ast/schema_ast/src/parser/helpers.rs: -------------------------------------------------------------------------------- 1 | use super::Rule; 2 | 3 | pub type Pair<'a> = pest::iterators::Pair<'a, Rule>; 4 | 5 | #[track_caller] 6 | pub fn parsing_catch_all(token: &Pair<'_>, kind: &str) { 7 | match token.as_rule() { 8 | Rule::empty_lines | Rule::trailing_comment | Rule::comment_block => {} 9 | x => unreachable!( 10 | "Encountered impossible {} during parsing: {:?} {:?}", 11 | kind, 12 | &x, 13 | token.clone().tokens() 14 | ), 15 | } 16 | } -------------------------------------------------------------------------------- /crates/ast/schema_ast/src/parser/parse_attribute.rs: -------------------------------------------------------------------------------- 1 | use super::{ 2 | helpers::{parsing_catch_all, Pair}, 3 | Rule, 4 | }; 5 | use crate::{ast::*, parser::parse_arguments::parse_arguments_list}; 6 | 7 | pub(crate) fn parse_attribute(pair: Pair<'_>, diagnostics: &mut diagnostics::Diagnostics) -> Attribute { 8 | let span = Span::from(pair.as_span()); 9 | let mut name = None; 10 | let mut arguments: ArgumentsList = ArgumentsList::default(); 11 | 12 | for current in pair.into_inner() { 13 | match current.as_rule() { 14 | Rule::path => name = Some(current.into()), 15 | Rule::arguments_list => parse_arguments_list(current, &mut arguments, diagnostics), 16 | _ => parsing_catch_all(¤t, "attribute"), 17 | } 18 | } 19 | 20 | let name = name.unwrap(); 21 | Attribute { name, arguments, span } 22 | } -------------------------------------------------------------------------------- /crates/ast/schema_ast/src/renderer.rs: -------------------------------------------------------------------------------- 1 | mod table; 2 | 3 | pub(crate) use table::TableFormat; 4 | 5 | pub(crate) trait LineWriteable { 6 | fn write(&mut self, param: &str); 7 | fn end_line(&mut self); 8 | } 9 | 10 | pub(crate) struct Renderer { 11 | pub stream: String, 12 | indent: usize, 13 | indent_width: usize, 14 | } 15 | 16 | impl Renderer { 17 | pub(crate) fn new(indent_width: usize) -> Renderer { 18 | Renderer { 19 | stream: String::new(), 20 | indent: 0, 21 | indent_width, 22 | } 23 | } 24 | 25 | pub(crate) fn indent_up(&mut self) { 26 | self.indent += 1 27 | } 28 | 29 | pub(crate) fn indent_down(&mut self) { 30 | if self.indent == 0 { 31 | panic!("Indentation error.") 32 | } 33 | self.indent -= 1 34 | } 35 | } 36 | 37 | impl LineWriteable for Renderer { 38 | fn write(&mut self, param: &str) { 39 | if self.stream.is_empty() || self.stream.ends_with('\n') { 40 | for _ in 0..(self.indent * self.indent_width) { 41 | self.stream.push(' '); 42 | } 43 | } 44 | 45 | self.stream.push_str(param); 46 | } 47 | 48 | fn end_line(&mut self) { 49 | self.stream.push('\n'); 50 | } 51 | } 52 | 53 | impl<'a> LineWriteable for &'a mut String { 54 | fn write(&mut self, param: &str) { 55 | self.push_str(param); 56 | } 57 | 58 | fn end_line(&mut self) { 59 | panic!("cannot end line in string builder"); 60 | } 61 | } -------------------------------------------------------------------------------- /crates/ast/schema_ast/src/source_file.rs: -------------------------------------------------------------------------------- 1 | use std::sync::Arc; 2 | 3 | /// A Prisma schema document. 4 | #[derive(Debug, Clone)] 5 | pub struct SourceFile { 6 | contents: Contents, 7 | } 8 | 9 | impl SourceFile { 10 | pub fn new_static(content: &'static str) -> Self { 11 | Self { 12 | contents: Contents::Static(content), 13 | } 14 | } 15 | 16 | pub fn new_allocated(s: Arc) -> Self { 17 | Self { 18 | contents: Contents::Allocated(s), 19 | } 20 | } 21 | 22 | pub fn as_str(&self) -> &str { 23 | match self.contents { 24 | Contents::Static(s) => s, 25 | Contents::Allocated(ref s) => s, 26 | } 27 | } 28 | } 29 | 30 | impl From<&str> for SourceFile { 31 | fn from(s: &str) -> Self { 32 | Self::new_allocated(Arc::from(s.to_owned().into_boxed_str())) 33 | } 34 | } 35 | 36 | impl From> for SourceFile { 37 | fn from(s: Box) -> Self { 38 | Self::new_allocated(Arc::from(s)) 39 | } 40 | } 41 | 42 | impl From> for SourceFile { 43 | fn from(s: Arc) -> Self { 44 | Self::new_allocated(s) 45 | } 46 | } 47 | 48 | impl From for SourceFile { 49 | fn from(s: String) -> Self { 50 | Self::new_allocated(Arc::from(s.into_boxed_str())) 51 | } 52 | } 53 | 54 | #[derive(Debug, Clone)] 55 | enum Contents { 56 | Static(&'static str), 57 | Allocated(Arc), 58 | } -------------------------------------------------------------------------------- /crates/format/turboprisma_fmt/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "turboprisma_fmt" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | colored = "2" 8 | dmmf = { path = "../../query_engine/dmmf"} 9 | lsp-types = "0.91.1" 10 | log = "0.4.14" 11 | indoc = "1" 12 | enumflags2 = "0.7" 13 | serde_json = { version = "1", features = ["float_roundtrip", "preserve_order"] } 14 | serde = { version = "1", features = ["derive"] } 15 | psl = { path = "../../ast/psl" } 16 | 17 | [target.'cfg(not(target_arch = "wasm32"))'.dependencies] 18 | structopt = "0.3" 19 | 20 | [dev-dependencies] 21 | dissimilar = "1.0.3" 22 | once_cell = "1.9.0" 23 | expect-test = "1" 24 | 25 | [features] 26 | # sigh please don't ask :( 27 | vendored-openssl = [] 28 | -------------------------------------------------------------------------------- /crates/format/turboprisma_fmt/build.rs: -------------------------------------------------------------------------------- 1 | use std::process::Command; 2 | 3 | fn store_git_commit_hash() { 4 | let output = Command::new("git").args(["rev-parse", "HEAD"]).output().unwrap(); 5 | let git_hash = String::from_utf8(output.stdout).unwrap(); 6 | println!("cargo:rustc-env=GIT_HASH={git_hash}"); 7 | } 8 | 9 | fn main() { 10 | store_git_commit_hash(); 11 | } 12 | -------------------------------------------------------------------------------- /crates/format/turboprisma_fmt/schema.prisma: -------------------------------------------------------------------------------- 1 | datasource db { 2 | provider = "postgresql" 3 | url = env("DATABASE_URL") 4 | } 5 | -------------------------------------------------------------------------------- /crates/format/turboprisma_fmt/src/actions.rs: -------------------------------------------------------------------------------- 1 | pub(crate) fn run(schema: &str) -> String { 2 | let datamodel_result = psl::parse_configuration(schema); 3 | 4 | match datamodel_result { 5 | Ok(validated_configuration) => { 6 | if validated_configuration.datasources.len() != 1 { 7 | "[]".to_string() 8 | } else if let Some(datasource) = validated_configuration.datasources.first() { 9 | let available_referential_actions = datasource 10 | .active_connector 11 | .referential_actions() 12 | .iter() 13 | .map(|act| format!("{act:?}")) 14 | .collect::>(); 15 | 16 | serde_json::to_string(&available_referential_actions).expect("Failed to render JSON") 17 | } else { 18 | "[]".to_string() 19 | } 20 | } 21 | _ => "[]".to_owned(), 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /crates/format/turboprisma_fmt/src/code_actions/relation_mode.rs: -------------------------------------------------------------------------------- 1 | use lsp_types::{CodeAction, CodeActionKind, CodeActionOrCommand}; 2 | use psl::schema_ast::ast::SourceConfig; 3 | 4 | pub(crate) fn edit_referential_integrity( 5 | actions: &mut Vec, 6 | params: &lsp_types::CodeActionParams, 7 | schema: &str, 8 | source: &SourceConfig, 9 | ) { 10 | let prop = match source.properties.iter().find(|p| p.name.name == "referentialIntegrity") { 11 | Some(prop) => prop, 12 | None => return, 13 | }; 14 | 15 | let span_diagnostics = match super::diagnostics_for_span(schema, ¶ms.context.diagnostics, source.span) { 16 | Some(sd) => sd, 17 | None => return, 18 | }; 19 | 20 | let diagnostics = 21 | match super::filter_diagnostics(span_diagnostics, "The `referentialIntegrity` attribute is deprecated.") { 22 | Some(value) => value, 23 | None => return, 24 | }; 25 | 26 | let edit = super::create_text_edit(schema, "relationMode".to_owned(), false, prop.name.span, params); 27 | 28 | let action = CodeAction { 29 | title: String::from("Rename property to relationMode"), 30 | kind: Some(CodeActionKind::QUICKFIX), 31 | edit: Some(edit), 32 | diagnostics: Some(diagnostics), 33 | ..Default::default() 34 | }; 35 | 36 | actions.push(CodeActionOrCommand::CodeAction(action)) 37 | } 38 | -------------------------------------------------------------------------------- /crates/format/turboprisma_fmt/src/format.rs: -------------------------------------------------------------------------------- 1 | use crate::FormatOpts; 2 | use psl::reformat; 3 | use std::{ 4 | fs::{self, File}, 5 | io::{self, BufWriter, Read, Write as _}, 6 | }; 7 | 8 | pub fn run(opts: FormatOpts) { 9 | let datamodel_string = match opts.input { 10 | Some(file_name) => { 11 | fs::read_to_string(&file_name).unwrap_or_else(|_| panic!("Unable to open file {}", file_name.display())) 12 | } 13 | None => { 14 | let mut buf = String::new(); 15 | 16 | io::stdin() 17 | .read_to_string(&mut buf) 18 | .expect("Unable to read from stdin."); 19 | 20 | buf 21 | } 22 | }; 23 | 24 | let reformatted = reformat(&datamodel_string, opts.tabwidth).unwrap_or(datamodel_string); 25 | match opts.output { 26 | Some(file_name) => { 27 | let file = File::open(&file_name).unwrap_or_else(|_| panic!("Unable to open file {}", file_name.display())); 28 | let mut file = BufWriter::new(file); 29 | file.write_all(reformatted.as_bytes()).unwrap(); 30 | } 31 | None => io::stdout().lock().write_all(reformatted.as_bytes()).unwrap(), 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /crates/format/turboprisma_fmt/src/preview.rs: -------------------------------------------------------------------------------- 1 | use psl::ALL_PREVIEW_FEATURES; 2 | 3 | pub fn run() -> String { 4 | serde_json::to_string(&ALL_PREVIEW_FEATURES.active_features().iter().collect::>()).unwrap() 5 | } 6 | -------------------------------------------------------------------------------- /crates/format/turboprisma_fmt_wasm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "turboprisma-fmt-wasm" 3 | description = "Internal package for @turboprisma/sdk." 4 | version = "0.1.0" 5 | edition = "2021" 6 | repository = "https://github.com/DavidHancu/turboprisma" 7 | license = "Apache-2.0" 8 | 9 | [lib] 10 | crate-type = ["cdylib"] 11 | 12 | [dependencies] 13 | wasm-bindgen = "=0.2.83" 14 | wasm-logger = { version = "0.2.0", optional = true } 15 | turboprisma_fmt = { path = "../turboprisma_fmt" } 16 | -------------------------------------------------------------------------------- /crates/format/turboprisma_fmt_wasm/README.md: -------------------------------------------------------------------------------- 1 | # @turboprisma/turboprisma-fmt-wasm 2 | 3 | This directory only contains build logic to package the `turboprisma-fmt` engine 4 | into a Node package as a WASM module. All the functionality is implemented in 5 | other parts of Turboprisma. 6 | 7 | The published NPM package is internal to Turboprisma. Its API will break without prior warning. 8 | 9 | If you are looking for a stable, production-ready, developer SDK for Turboprisma, read [this](https://turboprisma.js.org/docs/sdk). -------------------------------------------------------------------------------- /crates/format/turboprisma_fmt_wasm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@turboprisma/turboprisma-fmt-wasm", 3 | "version": null, 4 | "description": "The WASM package for turboprisma-fmt", 5 | "main": "src/turboprisma_fmt_build.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/DavidHancu/turboprisma", 12 | "directory": "crates/format/turboprisma_fmt_wasm" 13 | }, 14 | "author": "DavidHancu", 15 | "license": "Apache-2.0", 16 | "homepage": "https://turboprisma.js.org" 17 | } 18 | -------------------------------------------------------------------------------- /crates/libs/prisma_value/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "prisma_value" 4 | version = "0.1.0" 5 | 6 | [dependencies] 7 | base64 = "0.12" 8 | chrono = { version = "0.4", features = ["serde"] } 9 | once_cell = "1.3" 10 | regex = "1.2" 11 | bigdecimal = "0.3" 12 | serde_json = { version = "1", features = ["float_roundtrip", "preserve_order"] } 13 | serde = { version = "1", features = ["derive"] } 14 | uuid = { version = "1", features = ["serde"] } -------------------------------------------------------------------------------- /crates/libs/prisma_value/src/arithmetic.rs: -------------------------------------------------------------------------------- 1 | //! Note: Only number operations are implemented at the moment. 2 | use super::*; 3 | use std::ops::*; 4 | 5 | /// Used right now to reduce code duplication, probably needs to be scrapped once we need anything beyond that. 6 | macro_rules! number_operation { 7 | ($trait_:ident, $fname:ident, $op:tt) => { 8 | impl $trait_ for PrismaValue { 9 | type Output = PrismaValue; 10 | 11 | fn $fname(self, rhs: Self) -> Self::Output { 12 | match (self, rhs) { 13 | (PrismaValue::Null, _) | (_, PrismaValue::Null) => PrismaValue::Null, 14 | 15 | (PrismaValue::Int(l), PrismaValue::Int(r)) => PrismaValue::Int(l $op r), 16 | (PrismaValue::Int(l), PrismaValue::Float(r)) => { 17 | PrismaValue::Int(l $op r.to_i64().expect("Unable to convert decimal to i64")) 18 | } 19 | 20 | (PrismaValue::Float(l), PrismaValue::Int(r)) => PrismaValue::Float( 21 | l $op (BigDecimal::from_i64(r).expect("Invalid i64 to decimal conversion.")), 22 | ), 23 | 24 | (PrismaValue::Float(l), PrismaValue::Float(r)) => PrismaValue::Float(l $op r), 25 | 26 | _ => unimplemented!(), 27 | } 28 | } 29 | } 30 | } 31 | } 32 | 33 | number_operation!(Add, add, +); 34 | number_operation!(Sub, sub, -); 35 | number_operation!(Div, div, /); 36 | number_operation!(Mul, mul, *); 37 | -------------------------------------------------------------------------------- /crates/libs/prisma_value/src/error.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::Cow; 2 | use std::error::Error; 3 | use std::fmt::Display; 4 | 5 | #[derive(Debug)] 6 | pub struct ConversionFailure { 7 | pub from: Cow<'static, str>, 8 | pub to: Cow<'static, str>, 9 | } 10 | 11 | impl Error for ConversionFailure {} 12 | 13 | impl Display for ConversionFailure { 14 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 15 | write!(f, "Could not convert from `{}` to `{}`", self.from, self.to) 16 | } 17 | } 18 | 19 | impl ConversionFailure { 20 | pub fn new(from: A, to: B) -> ConversionFailure 21 | where 22 | A: Into>, 23 | B: Into>, 24 | { 25 | ConversionFailure { 26 | from: from.into(), 27 | to: to.into(), 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /crates/query_engine/dml/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dml" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | prisma_value = { path = "../../libs/prisma_value" } 8 | psl_core = { path = "../../ast/psl_core" } 9 | 10 | uuid = { version = "1", features = ["serde"] } 11 | cuid = { version = "1.2", optional = true } 12 | nanoid = { version = "0.4.0", optional = true } 13 | chrono = { version = "0.4.6", features = ["serde"] } 14 | enumflags2 = "0.7" 15 | indoc = "1" 16 | either = "1.6" 17 | 18 | serde_json = { version = "1", features = ["float_roundtrip", "preserve_order"] } 19 | serde = { version = "1", features = ["derive"] } 20 | 21 | [features] 22 | # Support for generating default UUID, CUID, nanoid and datetime values. This 23 | # implies random number generation works, so it won't compile on targets like 24 | # wasm32. 25 | default_generators = ["uuid/v4", "cuid", "nanoid"] 26 | -------------------------------------------------------------------------------- /crates/query_engine/dml/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! This module contains the models representing the Datamodel part of a Prisma schema. 2 | //! It contains the main data structures that the engines can build upon. 3 | 4 | #![allow(clippy::derive_partial_eq_without_eq)] 5 | 6 | mod datamodel; 7 | mod lift; 8 | 9 | pub mod composite_type; 10 | pub mod default_value; 11 | pub mod field; 12 | pub mod model; 13 | pub mod native_type_instance; 14 | pub mod relation_info; 15 | pub mod scalars; 16 | pub mod traits; 17 | 18 | pub use self::{ 19 | composite_type::*, datamodel::*, default_value::*, field::*, lift::dml_default_kind, model::*, 20 | native_type_instance::*, relation_info::*, scalars::*, traits::*, 21 | }; 22 | pub use prisma_value::{self, PrismaValue}; 23 | pub use psl_core::parser_database::{ast::FieldArity, IndexType, ReferentialAction}; 24 | 25 | use psl_core::ValidatedSchema; 26 | 27 | /// Find the model mapping to the passed in database name. 28 | pub fn find_model_by_db_name<'a>(datamodel: &'a Datamodel, db_name: &str) -> Option<&'a Model> { 29 | datamodel 30 | .models 31 | .iter() 32 | .find(|model| model.database_name() == Some(db_name) || model.name == db_name) 33 | } 34 | 35 | /// Validated schema -> dml::Datamodel. 36 | pub fn lift(schema: &ValidatedSchema) -> crate::Datamodel { 37 | lift::LiftAstToDml::new(&schema.db, schema.connector).lift() 38 | } 39 | -------------------------------------------------------------------------------- /crates/query_engine/dml/src/native_type_instance.rs: -------------------------------------------------------------------------------- 1 | use psl_core::datamodel_connector::{Connector, NativeTypeInstance as PslNativeTypeInstance}; 2 | use std::fmt; 3 | 4 | /// Represents an instance of a native type declared in the Prisma schema. 5 | #[derive(Clone)] 6 | pub struct NativeTypeInstance { 7 | pub native_type: PslNativeTypeInstance, 8 | pub connector: &'static dyn Connector, 9 | } 10 | 11 | impl fmt::Debug for NativeTypeInstance { 12 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 13 | f.write_str(&self.connector.native_type_to_string(&self.native_type)) 14 | } 15 | } 16 | 17 | impl PartialEq for NativeTypeInstance { 18 | fn eq(&self, other: &Self) -> bool { 19 | self.connector.native_type_to_parts(&self.native_type) 20 | == other.connector.native_type_to_parts(&other.native_type) 21 | } 22 | } 23 | 24 | impl NativeTypeInstance { 25 | pub fn new(native_type: PslNativeTypeInstance, connector: &'static dyn Connector) -> Self { 26 | NativeTypeInstance { native_type, connector } 27 | } 28 | 29 | pub fn inner(&self) -> &PslNativeTypeInstance { 30 | &self.native_type 31 | } 32 | 33 | pub fn deserialize_native_type(&self) -> &T { 34 | self.native_type.downcast_ref() 35 | } 36 | 37 | pub fn name(&self) -> &'static str { 38 | self.connector.native_type_to_parts(&self.native_type).0 39 | } 40 | 41 | pub fn args(&self) -> Vec { 42 | self.connector.native_type_to_parts(&self.native_type).1 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /crates/query_engine/dml/src/relation_info.rs: -------------------------------------------------------------------------------- 1 | use psl_core::{parser_database as db, schema_ast::ast}; 2 | 3 | /// Holds information about a relation field. 4 | #[derive(Debug, PartialEq, Clone)] 5 | pub struct RelationInfo { 6 | /// The target model of the relation. 7 | pub referenced_model: ast::ModelId, 8 | /// The fields forming the relation. 9 | pub fields: Vec, 10 | /// The target field of the relation a.k.a. `references` 11 | pub references: Vec, 12 | /// The name of the relation. Internally, an empty string signals no name. 13 | pub name: String, 14 | /// Foreign Key Constraint Name if there is one 15 | pub fk_name: Option, 16 | /// A strategy indicating what happens when 17 | /// a related node is deleted. 18 | pub on_delete: Option, 19 | /// A strategy indicating what happens when 20 | /// a related node is updated. 21 | pub on_update: Option, 22 | } 23 | 24 | impl RelationInfo { 25 | /// Creates a new relation info for the 26 | /// given target model. 27 | pub fn new(referenced_model: ast::ModelId) -> RelationInfo { 28 | RelationInfo { 29 | referenced_model, 30 | fields: Vec::new(), 31 | references: Vec::new(), 32 | name: String::new(), 33 | fk_name: None, 34 | on_delete: None, 35 | on_update: None, 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /crates/query_engine/dml/src/traits.rs: -------------------------------------------------------------------------------- 1 | pub trait WithName { 2 | fn name(&self) -> &String; 3 | 4 | fn set_name(&mut self, name: &str); //Todo do not take a ref 5 | } 6 | 7 | pub trait WithDatabaseName: WithName { 8 | fn database_name(&self) -> Option<&str>; 9 | 10 | fn final_database_name(&self) -> &str { 11 | self.database_name().unwrap_or_else(|| self.name()) 12 | } 13 | 14 | fn set_database_name(&mut self, database_name: Option); 15 | } 16 | -------------------------------------------------------------------------------- /crates/query_engine/dmmf/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "dmmf" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | bigdecimal = "0.3.0" 8 | schema = { path = "../schema" } 9 | schema_builder = { path = "../schema_builder" } 10 | indexmap = { version = "1.7", features = ["serde-1"] } 11 | prisma_models = { path = "../prisma_models" } 12 | psl = { path = "../../ast/psl" } 13 | serde_json = { version = "1", features = ["float_roundtrip", "preserve_order"] } 14 | serde = { version = "1", features = ["derive"] } 15 | 16 | [dev-dependencies] 17 | expect-test = "1.2.2" 18 | indoc = "1.0.3" 19 | pretty_assertions = "1" 20 | -------------------------------------------------------------------------------- /crates/query_engine/dmmf/src/ast_builders/mod.rs: -------------------------------------------------------------------------------- 1 | mod datamodel_ast_builder; 2 | mod schema_ast_builder; 3 | 4 | pub use datamodel_ast_builder::*; 5 | pub use schema_ast_builder::*; 6 | -------------------------------------------------------------------------------- /crates/query_engine/dmmf/src/ast_builders/schema_ast_builder/enum_renderer.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | pub(crate) fn render_enum_types(ctx: &mut RenderContext, enum_types: &[EnumTypeRef]) { 4 | let mut borrows: Vec<_> = enum_types.iter().collect(); 5 | 6 | borrows.sort_by(|a, b| a.name().cmp(b.name())); 7 | borrows.into_iter().for_each(|et| DmmfEnumRenderer::new(et).render(ctx)); 8 | } 9 | 10 | pub struct DmmfEnumRenderer { 11 | enum_type: EnumType, 12 | } 13 | 14 | impl Renderer for DmmfEnumRenderer { 15 | fn render(&self, ctx: &mut RenderContext) { 16 | let ident = self.enum_type.identifier(); 17 | if ctx.already_rendered(ident) { 18 | return; 19 | } 20 | 21 | let values = self.format_enum_values(); 22 | let rendered = DmmfEnum { 23 | name: self.enum_type.name().to_owned(), 24 | values, 25 | }; 26 | 27 | ctx.add_enum(ident.clone(), rendered); 28 | } 29 | } 30 | 31 | impl DmmfEnumRenderer { 32 | pub fn new(enum_type: &EnumType) -> DmmfEnumRenderer { 33 | DmmfEnumRenderer { 34 | enum_type: enum_type.clone(), 35 | } 36 | } 37 | 38 | fn format_enum_values(&self) -> Vec { 39 | match &self.enum_type { 40 | EnumType::String(s) => s.values().to_owned(), 41 | EnumType::Database(dbt) => dbt.external_values(), 42 | EnumType::FieldRef(f) => f.values(), 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /crates/query_engine/dmmf/src/ast_builders/schema_ast_builder/schema_renderer.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | pub struct DmmfSchemaRenderer { 4 | query_schema: QuerySchemaRef, 5 | } 6 | 7 | impl Renderer for DmmfSchemaRenderer { 8 | fn render(&self, ctx: &mut RenderContext) { 9 | // This ensures that all enums are rendered, even if not reached by the output and input types. 10 | render_enum_types(ctx, self.query_schema.enum_types()); 11 | render_output_type(&self.query_schema.query, ctx); 12 | render_output_type(&self.query_schema.mutation, ctx); 13 | } 14 | } 15 | 16 | impl DmmfSchemaRenderer { 17 | pub fn new(query_schema: QuerySchemaRef) -> DmmfSchemaRenderer { 18 | DmmfSchemaRenderer { query_schema } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /crates/query_engine/dmmf/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod ast_builders; 2 | mod serialization_ast; 3 | 4 | #[cfg(test)] 5 | mod tests; 6 | 7 | pub use serialization_ast::DataModelMetaFormat; 8 | 9 | use ast_builders::{schema_to_dmmf, DmmfQuerySchemaRenderer}; 10 | use schema::{QuerySchemaRef, QuerySchemaRenderer}; 11 | use std::sync::Arc; 12 | 13 | pub fn dmmf_json_from_schema(schema: &str) -> String { 14 | let dmmf = dmmf_from_schema(schema); 15 | serde_json::to_string(&dmmf).unwrap() 16 | } 17 | 18 | pub fn dmmf_from_schema(schema: &str) -> DataModelMetaFormat { 19 | let schema = Arc::new(psl::parse_schema(schema).unwrap()); 20 | let internal_data_model = prisma_models::convert(schema); 21 | from_precomputed_parts(Arc::new(schema_builder::build(internal_data_model, true))) 22 | } 23 | 24 | pub fn from_precomputed_parts(query_schema: QuerySchemaRef) -> DataModelMetaFormat { 25 | let data_model = schema_to_dmmf(&query_schema.internal_data_model.schema); 26 | let (schema, mappings) = DmmfQuerySchemaRenderer::render(query_schema); 27 | 28 | DataModelMetaFormat { 29 | data_model, 30 | schema, 31 | mappings, 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /crates/query_engine/dmmf/src/serialization_ast/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod datamodel_ast; 2 | pub mod mappings_ast; 3 | pub mod schema_ast; 4 | 5 | pub use datamodel_ast::*; 6 | pub use mappings_ast::*; 7 | pub use schema_ast::*; 8 | 9 | use serde::Serialize; 10 | 11 | /// The main DMMF serialization struct. 12 | #[derive(Debug, Serialize)] 13 | #[serde(rename_all = "camelCase")] 14 | pub struct DataModelMetaFormat { 15 | #[serde(rename = "datamodel")] 16 | /// The datamodel AST. 17 | pub data_model: Datamodel, 18 | 19 | /// The query-engine API schema. 20 | pub schema: DmmfSchema, 21 | 22 | /// The operations map. Derived from the `schema`. 23 | pub mappings: DmmfOperationMappings, 24 | } 25 | -------------------------------------------------------------------------------- /crates/query_engine/dmmf/src/test-schemas/sqlite_ignore.prisma: -------------------------------------------------------------------------------- 1 | generator client { 2 | provider = "prisma-client-js" 3 | output = "../node_modules/.prisma/client" 4 | previewFeatures = [] 5 | } 6 | 7 | datasource db { 8 | provider = "sqlite" 9 | url = "file:dev.db" 10 | } 11 | 12 | /// User model comment 13 | model User { 14 | id String @id @default(uuid()) 15 | email String @unique 16 | age Int 17 | /// name comment 18 | name String? 19 | posts Post[] @ignore 20 | } 21 | 22 | model Post { 23 | id String @id @default(cuid()) 24 | createdAt DateTime @default(now()) 25 | updatedAt DateTime @updatedAt 26 | published Boolean 27 | title String 28 | content String? 29 | authorId String? 30 | author User? @relation(fields: [authorId], references: [id]) 31 | @@ignore 32 | } 33 | -------------------------------------------------------------------------------- /crates/query_engine/dmmf/src/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::dmmf_from_schema; 2 | 3 | #[test] 4 | fn sqlite_ignore() { 5 | let dmmf = dmmf_from_schema(include_str!("./test-schemas/sqlite_ignore.prisma")); 6 | 7 | // The Post model is ignored. 8 | assert_eq!(dmmf.data_model.models.len(), 1); 9 | assert_eq!(dmmf.mappings.model_operations.len(), 1); 10 | } 11 | -------------------------------------------------------------------------------- /crates/query_engine/dmmf/test_files/functions.prisma: -------------------------------------------------------------------------------- 1 | model User { 2 | id Int @id 3 | createdAt DateTime @default(now()) 4 | someId String @default(cuid()) @unique 5 | } 6 | -------------------------------------------------------------------------------- /crates/query_engine/dmmf/test_files/ignore.json: -------------------------------------------------------------------------------- 1 | { 2 | "enums": [], 3 | "models": [ 4 | { 5 | "name": "User", 6 | "dbName": null, 7 | "fields": [ 8 | { 9 | "name": "id", 10 | "kind": "scalar", 11 | "isList": false, 12 | "isRequired": true, 13 | "isUnique": false, 14 | "isId": true, 15 | "isReadOnly": false, 16 | "type": "Int", 17 | "hasDefaultValue": true, 18 | "default": { 19 | "name": "autoincrement", 20 | "args": [] 21 | }, 22 | "isGenerated": false, 23 | "isUpdatedAt": false 24 | }, 25 | { 26 | "name": "ip", 27 | "kind": "scalar", 28 | "isList": false, 29 | "isRequired": true, 30 | "isUnique": true, 31 | "isId": false, 32 | "isReadOnly": false, 33 | "type": "Int", 34 | "hasDefaultValue": true, 35 | "default": { 36 | "name": "dbgenerated", 37 | "args": [ 38 | "sqrt(4)" 39 | ] 40 | }, 41 | "isGenerated": false, 42 | "isUpdatedAt": false 43 | } 44 | ], 45 | "isGenerated": false, 46 | "primaryKey": null, 47 | "uniqueFields": [], 48 | "uniqueIndexes": [] 49 | } 50 | ], 51 | "types": [] 52 | } 53 | -------------------------------------------------------------------------------- /crates/query_engine/dmmf/test_files/ignore.prisma: -------------------------------------------------------------------------------- 1 | model Post { 2 | id Int 3 | user_ip Int 4 | User User @relation(fields: [user_ip], references: [ip]) 5 | 6 | @@ignore 7 | } 8 | 9 | model User { 10 | id Int @id @default(autoincrement()) 11 | ip Int @unique @default(dbgenerated("sqrt(4)")) 12 | usp Unsupported("something") 13 | Post Post[] @ignore 14 | } -------------------------------------------------------------------------------- /crates/query_engine/dmmf/test_files/source.json: -------------------------------------------------------------------------------- 1 | { 2 | "enums": [], 3 | "models": [], 4 | "types": [] 5 | } 6 | -------------------------------------------------------------------------------- /crates/query_engine/dmmf/test_files/source.prisma: -------------------------------------------------------------------------------- 1 | datasource pg1 { 2 | provider = "postgresql" 3 | url = "postgresql://" 4 | } 5 | -------------------------------------------------------------------------------- /crates/query_engine/dmmf/test_files/source_with_comments.json: -------------------------------------------------------------------------------- 1 | { 2 | "enums": [], 3 | "models": [ 4 | { 5 | "name": "Author", 6 | "dbName": null, 7 | "fields": [ 8 | { 9 | "name": "id", 10 | "kind": "scalar", 11 | "isList": false, 12 | "isRequired": true, 13 | "isUnique": false, 14 | "isId": true, 15 | "isReadOnly": false, 16 | "type": "Int", 17 | "hasDefaultValue": false, 18 | "isGenerated": false, 19 | "isUpdatedAt": false 20 | }, 21 | { 22 | "name": "name", 23 | "kind": "scalar", 24 | "isList": false, 25 | "isRequired": false, 26 | "isUnique": false, 27 | "isId": false, 28 | "isReadOnly": false, 29 | "type": "String", 30 | "hasDefaultValue": false, 31 | "isGenerated": false, 32 | "isUpdatedAt": false, 33 | "documentation": "Name of the author." 34 | } 35 | ], 36 | "isGenerated": false, 37 | "documentation": "My author model.", 38 | "primaryKey": null, 39 | "uniqueFields": [], 40 | "uniqueIndexes": [] 41 | } 42 | ], 43 | "types": [] 44 | } 45 | -------------------------------------------------------------------------------- /crates/query_engine/dmmf/test_files/source_with_comments.prisma: -------------------------------------------------------------------------------- 1 | /// Super cool postgres source. 2 | datasource pg1 { 3 | provider = "postgresql" 4 | url = "postgresql://" 5 | } 6 | 7 | /// My author model. 8 | model Author { 9 | id Int @id 10 | /// Name of the author. 11 | name String? 12 | } 13 | -------------------------------------------------------------------------------- /crates/query_engine/dmmf/test_files/source_with_generator.json: -------------------------------------------------------------------------------- 1 | { 2 | "enums": [], 3 | "models": [ 4 | { 5 | "name": "Author", 6 | "dbName": null, 7 | "fields": [ 8 | { 9 | "name": "id", 10 | "kind": "scalar", 11 | "isList": false, 12 | "isRequired": true, 13 | "isUnique": false, 14 | "isId": true, 15 | "isReadOnly": false, 16 | "type": "Int", 17 | "hasDefaultValue": false, 18 | "isGenerated": false, 19 | "isUpdatedAt": false 20 | }, 21 | { 22 | "name": "name", 23 | "kind": "scalar", 24 | "isList": false, 25 | "isRequired": false, 26 | "isUnique": false, 27 | "isId": false, 28 | "isReadOnly": false, 29 | "type": "String", 30 | "hasDefaultValue": false, 31 | "isGenerated": false, 32 | "isUpdatedAt": false 33 | } 34 | ], 35 | "isGenerated": false, 36 | "primaryKey": null, 37 | "uniqueFields": [], 38 | "uniqueIndexes": [] 39 | } 40 | ], 41 | "types": [] 42 | } 43 | -------------------------------------------------------------------------------- /crates/query_engine/dmmf/test_files/source_with_generator.prisma: -------------------------------------------------------------------------------- 1 | generator js { 2 | provider = "javascript" 3 | output = "./client" 4 | binaryTargets = ["a", "b"] 5 | extra_config = "test" 6 | } 7 | 8 | generator foo { 9 | provider = "bar" 10 | } 11 | 12 | model Author { 13 | id Int @id 14 | name String? 15 | } 16 | -------------------------------------------------------------------------------- /crates/query_engine/dmmf/test_files/views.prisma: -------------------------------------------------------------------------------- 1 | generator client { 2 | provider = "prisma-client-js" 3 | previewFeatures = ["views"] 4 | } 5 | 6 | model User { 7 | id String @id 8 | email String @unique 9 | name String? 10 | profile Profile? 11 | } 12 | model Profile { 13 | id String @id 14 | bio String 15 | user User @relation(fields: [userId], references: [id]) 16 | userId String @unique 17 | } 18 | 19 | view UserInfo { 20 | id String @id 21 | email String 22 | name String 23 | bio String 24 | } 25 | -------------------------------------------------------------------------------- /crates/query_engine/dmmf/test_files/without_relation_name.prisma: -------------------------------------------------------------------------------- 1 | model User { 2 | id Int @id 3 | posts Post[] 4 | } 5 | 6 | model Post { 7 | id Int @id 8 | userId Int 9 | user User @relation(fields: [userId], references: [id]) 10 | } 11 | -------------------------------------------------------------------------------- /crates/query_engine/prisma_models/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | edition = "2021" 3 | name = "prisma_models" 4 | version = "0.0.0" 5 | 6 | [dependencies] 7 | chrono = { version = "0.4", features = ["serde"] } 8 | dml = { path = "../dml" } 9 | itertools = "0.10" 10 | prisma_value = { path = "../../libs/prisma_value" } 11 | bigdecimal = "0.3" 12 | serde_json = { version = "1.0", features = ["float_roundtrip"] } 13 | thiserror = "1.0" 14 | psl = { path = "../../ast/psl" } 15 | 16 | [features] 17 | default_generators = ["dml/default_generators"] 18 | -------------------------------------------------------------------------------- /crates/query_engine/prisma_models/src/composite_type.rs: -------------------------------------------------------------------------------- 1 | use crate::Field; 2 | use psl::schema_ast::ast; 3 | 4 | pub type CompositeType = crate::Zipper; 5 | 6 | impl CompositeType { 7 | pub fn name(&self) -> &str { 8 | self.walker().name() 9 | } 10 | 11 | pub fn fields(&self) -> impl Iterator + '_ { 12 | self.walker().fields().map(|f| Field::from((self.dm.clone(), f))) 13 | } 14 | 15 | pub fn find_field(&self, prisma_name: &str) -> Option { 16 | self.fields().into_iter().find(|f| f.name() == prisma_name) 17 | } 18 | 19 | pub fn find_field_by_db_name(&self, db_name: &str) -> Option { 20 | self.fields().into_iter().find(|f| f.db_name() == db_name) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /crates/query_engine/prisma_models/src/convert.rs: -------------------------------------------------------------------------------- 1 | use crate::InternalDataModel; 2 | use std::sync::Arc; 3 | 4 | pub fn convert(schema: Arc) -> InternalDataModel { 5 | InternalDataModel { schema } 6 | } 7 | -------------------------------------------------------------------------------- /crates/query_engine/prisma_models/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod composite_type; 2 | mod convert; 3 | mod error; 4 | mod field; 5 | mod field_selection; 6 | mod fields; 7 | mod internal_data_model; 8 | mod model; 9 | mod order_by; 10 | mod parent_container; 11 | mod prisma_value_ext; 12 | mod projections; 13 | mod record; 14 | mod relation; 15 | mod selection_result; 16 | mod zipper; 17 | 18 | pub mod pk; 19 | pub mod prelude; 20 | 21 | pub use self::zipper::*; 22 | pub use composite_type::*; 23 | pub use convert::convert; 24 | pub use dml; 25 | pub use error::*; 26 | pub use field::*; 27 | pub use field_selection::*; 28 | pub use fields::*; 29 | pub use internal_data_model::*; 30 | pub use model::*; 31 | pub use order_by::*; 32 | pub use prisma_value_ext::*; 33 | pub use projections::*; 34 | pub use record::*; 35 | pub use relation::*; 36 | pub use selection_result::*; 37 | 38 | // Re-exports 39 | pub use prisma_value::*; 40 | pub use psl::{self, parser_database::walkers, schema_ast::ast}; 41 | 42 | pub type Result = std::result::Result; 43 | -------------------------------------------------------------------------------- /crates/query_engine/prisma_models/src/pk.rs: -------------------------------------------------------------------------------- 1 | use crate::{ScalarFieldRef, ScalarFieldWeak}; 2 | 3 | #[derive(Debug, Clone)] 4 | pub struct PrimaryKey { 5 | pub alias: Option, 6 | pub(crate) fields: Vec, 7 | } 8 | 9 | impl PrimaryKey { 10 | pub fn fields(&self) -> Vec { 11 | self.fields.clone() 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /crates/query_engine/prisma_models/src/prelude.rs: -------------------------------------------------------------------------------- 1 | pub use crate::error::*; 2 | pub use crate::field::*; 3 | pub use crate::field_selection::*; 4 | pub use crate::fields::*; 5 | pub use crate::internal_data_model::*; 6 | pub use crate::model::*; 7 | pub use crate::order_by::*; 8 | pub use crate::parent_container::*; 9 | pub use crate::projections::*; 10 | pub use crate::record::*; 11 | pub use crate::relation::*; 12 | pub use crate::selection_result::*; 13 | 14 | pub use dml::{self, prisma_value::*}; 15 | -------------------------------------------------------------------------------- /crates/query_engine/prisma_models/src/projections/mod.rs: -------------------------------------------------------------------------------- 1 | mod model_projection; 2 | 3 | pub use model_projection::*; 4 | -------------------------------------------------------------------------------- /crates/query_engine/prisma_models/src/zipper.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | psl::{parser_database::walkers::Walker, schema_ast::ast}, 3 | InternalDataModelRef, 4 | }; 5 | use std::{ 6 | fmt, 7 | hash::{Hash, Hasher}, 8 | }; 9 | 10 | // Invariant: InternalDataModel must not contain any Zipper, this would be a reference counting 11 | // cycle (memory leak). 12 | #[derive(Clone)] 13 | pub struct Zipper { 14 | pub id: I, 15 | pub dm: InternalDataModelRef, 16 | } 17 | 18 | impl fmt::Debug for Zipper { 19 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 20 | self.id.fmt(f) 21 | } 22 | } 23 | 24 | impl PartialEq for Zipper { 25 | fn eq(&self, other: &Self) -> bool { 26 | self.id.eq(&other.id) 27 | } 28 | } 29 | 30 | impl Eq for Zipper {} 31 | 32 | impl Zipper { 33 | pub fn walker(&self) -> Walker<'_, I> { 34 | self.dm.schema.db.walk(self.id) 35 | } 36 | } 37 | 38 | impl Hash for Zipper { 39 | fn hash(&self, state: &mut H) { 40 | self.id.hash(state) 41 | } 42 | } 43 | 44 | pub type InternalEnum = Zipper; 45 | pub type InternalEnumValue = Zipper; 46 | -------------------------------------------------------------------------------- /crates/query_engine/schema/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "schema" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | prisma_models = { path = "../prisma_models" } 8 | psl = { path = "../../ast/psl" } 9 | once_cell = "1.3" 10 | -------------------------------------------------------------------------------- /crates/query_engine/schema/src/renderer.rs: -------------------------------------------------------------------------------- 1 | use super::QuerySchemaRef; 2 | 3 | /// Trait that should be implemented in order to be able to render a query schema. 4 | pub trait QuerySchemaRenderer { 5 | fn render(query_schema: QuerySchemaRef) -> T; 6 | } 7 | -------------------------------------------------------------------------------- /crates/query_engine/schema_builder/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "schema_builder" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | schema = { path = "../schema" } 8 | prisma_models = { path = "../prisma_models" } 9 | once_cell = "1.3" 10 | psl = { path = "../../ast/psl" } 11 | 12 | [dev-dependencies.criterion] 13 | version = "0.4.0" 14 | default-features = false 15 | features = ["cargo_bench_support"] 16 | 17 | [[bench]] 18 | name = "schema_builder_bench" 19 | harness = false 20 | -------------------------------------------------------------------------------- /crates/query_engine/schema_builder/benches/schema_builder_bench.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 2 | 3 | const SMALL: (&str, &str) = ("small", include_str!("./standupbot.prisma")); 4 | const MEDIUM: (&str, &str) = ("medium", include_str!("./noalyss_folder.prisma")); 5 | const LARGE: (&str, &str) = ("large", include_str!("./odoo.prisma")); 6 | 7 | pub fn criterion_benchmark(c: &mut Criterion) { 8 | for (name, prisma_schema) in [SMALL, MEDIUM, LARGE] { 9 | let source_file: psl::SourceFile = prisma_schema.into(); 10 | 11 | c.bench_function(&format!("psl::validate ({name})"), |b| { 12 | b.iter(|| black_box(psl::validate(source_file.clone()))) 13 | }); 14 | 15 | let validated_schema = std::sync::Arc::new(psl::validate(source_file)); 16 | 17 | c.bench_function(&format!("prisma_models::convert ({name})"), |b| { 18 | b.iter(|| black_box(prisma_models::convert(validated_schema.clone()))) 19 | }); 20 | 21 | let idm = prisma_models::convert(validated_schema); 22 | 23 | c.bench_function(&format!("schema_builder::build ({name})"), |b| { 24 | b.iter(|| black_box(schema_builder::build(idm.clone(), true))); 25 | }); 26 | } 27 | } 28 | 29 | criterion_group!(benches, criterion_benchmark); 30 | criterion_main!(benches); 31 | -------------------------------------------------------------------------------- /crates/query_engine/schema_builder/src/input_types/fields/data_input_mapper/mod.rs: -------------------------------------------------------------------------------- 1 | mod create; 2 | mod update; 3 | 4 | pub(crate) use create::*; 5 | pub(crate) use update::*; 6 | 7 | use super::*; 8 | use prisma_models::prelude::*; 9 | 10 | // Todo: This isn't final, this is only the first draft to get structure into the 11 | // wild cross-dependency waste that was the create/update inputs. 12 | pub(crate) trait DataInputFieldMapper { 13 | fn map_all(&self, ctx: &mut BuilderContext, fields: &[Field]) -> Vec { 14 | fields 15 | .iter() 16 | .map(|field| match field { 17 | Field::Scalar(sf) if sf.is_list() => self.map_scalar_list(ctx, sf), 18 | Field::Scalar(sf) => self.map_scalar(ctx, sf), 19 | Field::Relation(rf) => self.map_relation(ctx, rf), 20 | Field::Composite(cf) => self.map_composite(ctx, cf), 21 | }) 22 | .collect() 23 | } 24 | 25 | fn map_scalar(&self, ctx: &mut BuilderContext, sf: &ScalarFieldRef) -> InputField; 26 | 27 | fn map_scalar_list(&self, ctx: &mut BuilderContext, sf: &ScalarFieldRef) -> InputField; 28 | 29 | fn map_relation(&self, ctx: &mut BuilderContext, rf: &RelationFieldRef) -> InputField; 30 | 31 | fn map_composite(&self, ctx: &mut BuilderContext, cf: &CompositeFieldRef) -> InputField; 32 | } 33 | -------------------------------------------------------------------------------- /crates/query_engine/schema_builder/src/input_types/fields/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod arguments; 2 | pub(crate) mod data_input_mapper; 3 | pub(crate) mod field_filter_types; 4 | pub(crate) mod field_ref_type; 5 | pub(crate) mod input_fields; 6 | 7 | use super::*; 8 | -------------------------------------------------------------------------------- /crates/query_engine/schema_builder/src/input_types/objects/connect_or_create_objects.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use constants::args; 3 | use mutations::create_one; 4 | 5 | /// Builds "CreateOrConnectNestedInput" input object types. 6 | pub(crate) fn nested_connect_or_create_input_object( 7 | ctx: &mut BuilderContext, 8 | parent_field: &RelationFieldRef, 9 | ) -> Option { 10 | let related_model = parent_field.related_model(); 11 | let where_object = filter_objects::where_unique_object_type(ctx, &related_model); 12 | 13 | if where_object.into_arc().is_empty() { 14 | return None; 15 | } 16 | 17 | let ident = Identifier::new( 18 | format!( 19 | "{}CreateOrConnectWithout{}Input", 20 | related_model.name(), 21 | capitalize(parent_field.related_field().name()) 22 | ), 23 | PRISMA_NAMESPACE, 24 | ); 25 | 26 | let create_types = create_one::create_one_input_types(ctx, &related_model, Some(parent_field)); 27 | 28 | match ctx.get_input_type(&ident) { 29 | None => { 30 | let input_object = Arc::new(init_input_object_type(ident.clone())); 31 | ctx.cache_input_type(ident, input_object.clone()); 32 | 33 | let fields = vec![ 34 | input_field(args::WHERE, InputType::object(where_object), None), 35 | input_field(args::CREATE, create_types, None), 36 | ]; 37 | 38 | input_object.set_fields(fields); 39 | Some(Arc::downgrade(&input_object)) 40 | } 41 | x => x, 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /crates/query_engine/schema_builder/src/input_types/objects/mod.rs: -------------------------------------------------------------------------------- 1 | pub(super) mod connect_or_create_objects; 2 | pub(super) mod filter_objects; 3 | pub(super) mod order_by_objects; 4 | pub(super) mod update_many_objects; 5 | pub(super) mod update_one_objects; 6 | pub(super) mod upsert_objects; 7 | 8 | use super::*; 9 | -------------------------------------------------------------------------------- /crates/query_engine/schema_builder/src/mutations/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod create_many; 2 | pub(crate) mod create_one; 3 | 4 | pub(crate) use create_many::create_many; 5 | pub(crate) use create_one::create_one; 6 | -------------------------------------------------------------------------------- /crates/query_engine/schema_builder/src/output_types/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod aggregation; 2 | pub(crate) mod field; 3 | pub(crate) mod mutation_type; 4 | pub(crate) mod objects; 5 | pub(crate) mod query_type; 6 | 7 | use super::*; 8 | -------------------------------------------------------------------------------- /crates/query_engine/schema_builder/src/output_types/objects/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod composite; 2 | pub mod model; 3 | 4 | use super::*; 5 | use crate::constants::output_fields::*; 6 | 7 | /// Initializes output object type caches on the context. 8 | /// This is a critical first step to ensure that all model and composite output 9 | /// object types are present and that subsequent schema computation has a base to rely on. 10 | /// Called only once at the very beginning of schema building. 11 | pub(crate) fn initialize_caches(ctx: &mut BuilderContext) { 12 | model::initialize_cache(ctx); 13 | composite::initialize_cache(ctx); 14 | 15 | model::initialize_fields(ctx); 16 | composite::initialize_fields(ctx); 17 | } 18 | 19 | pub(crate) fn affected_records_object_type(ctx: &mut BuilderContext) -> ObjectTypeWeakRef { 20 | let ident = Identifier::new("AffectedRowsOutput".to_owned(), PRISMA_NAMESPACE); 21 | return_cached_output!(ctx, &ident); 22 | 23 | let object_type = Arc::new(object_type( 24 | ident.clone(), 25 | vec![field(AFFECTED_COUNT, vec![], OutputType::int(), None)], 26 | None, 27 | )); 28 | 29 | ctx.cache_output_type(ident, object_type.clone()); 30 | Arc::downgrade(&object_type) 31 | } 32 | -------------------------------------------------------------------------------- /crates/turboprisma_cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "turboprisma_cli" 3 | version = "0.3.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | colored = "2.0.0" 10 | tiny-gradient = "0.1.0" 11 | serde = { version = "1", features = ["derive"] } 12 | serde_json = "1.0.93" 13 | turboprisma_fmt = { path = "../format/turboprisma_fmt" } 14 | relative-path = "1.8.0" 15 | regex = "1.7.1" 16 | lazy_static = "1.4.0" 17 | 18 | [dev-dependencies] 19 | criterion = { version = "0.3.5", features = ["async_tokio"] } -------------------------------------------------------------------------------- /crates/turboprisma_cli/src/commands/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod version; 2 | pub mod init; 3 | pub mod format; 4 | pub mod validate; -------------------------------------------------------------------------------- /crates/turboprisma_cli/src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod schema; 2 | pub mod env; 3 | pub mod install; -------------------------------------------------------------------------------- /crates/turboprisma_vm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "turboprisma_vm" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | dunce = "1.0.3" 8 | colored = "2.0.0" 9 | tiny-gradient = "0.1.0" -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "turboprisma-monorepo", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "tests" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/DavidHancu/turboprisma.git" 15 | }, 16 | "author": "DavidHancu", 17 | "license": "Apache-2.0", 18 | "bugs": { 19 | "url": "https://github.com/DavidHancu/turboprisma/issues" 20 | }, 21 | "homepage": "https://github.com/DavidHancu/turboprisma#readme", 22 | "devDependencies": { 23 | "semver": "^7.3.8" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/turboprisma-vm/README.MD: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 |

Turboprisma Version Manager

9 |
10 | 11 | 12 | 13 |
14 |
15 | What is Turboprisma Version Manager? 16 |   •   17 | Links 18 | 19 |
20 |
21 |
22 | 23 | ## What is Turboprisma Version Manager? 24 | 25 | Turboprisma Version Manager allows you to run the locally installed Turboprisma CLI while keeping most of the performance benefits of global installs. 26 | 27 | ## Links 28 | 29 | Check Turboprisma out - [Website](https://turboprisma.js.org) 30 | 31 | Read more about TVM - [Managing CLI Versions](https://turboprisma.js.org/go/tvm) -------------------------------------------------------------------------------- /packages/turboprisma-vm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "turboprisma-vm", 3 | "version": "1.0.0", 4 | "description": "Easy way to access local installs of Turboprisma without providing a full path or using package manager runners.", 5 | "bin": { 6 | "turboprisma-vm": "./turboprisma_cli", 7 | "tvm": "./turboprisma_cli" 8 | }, 9 | "homepage": "https://turboprisma.js.org", 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1", 12 | "postinstall": "node postInstall.js" 13 | }, 14 | "keywords": ["turbo", "prisma", "orm", "database", "runtime", "turboprisma", "dmmf", "schema", "parser"], 15 | "author": "DavidHancu", 16 | "license": "Apache-2.0", 17 | "optionalDependencies": { 18 | "@turboprisma/vm-cli-linux-x64": "1.0.0", 19 | "@turboprisma/vm-cli-linux-arm64": "1.0.0", 20 | "@turboprisma/vm-cli-darwin-x64": "1.0.0", 21 | "@turboprisma/vm-cli-darwin-arm64": "1.0.0", 22 | "@turboprisma/vm-cli-windows-x64": "1.0.0", 23 | "@turboprisma/vm-cli-windows-arm64": "1.0.0" 24 | }, 25 | "repository": "https://github.com/DavidHancu/turboprisma", 26 | "bugs": "https://github.com/DavidHancu/turboprisma/issues" 27 | } 28 | -------------------------------------------------------------------------------- /packages/turboprisma-vm/turboprisma_cli: -------------------------------------------------------------------------------- 1 | #/usr/bin/sh -------------------------------------------------------------------------------- /packages/turboprisma/README.MD: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 |

Turboprisma

9 |
10 | 11 | 12 | 13 |
14 |
15 | What is Turboprisma? 16 |   •   17 | Links 18 | 19 |
20 |
21 |
22 | 23 | ## What is Turboprisma? 24 | 25 | Turboprisma is a fast and performant Prisma runtime that provides an unified access framework, abstractions and new features on top of the Prisma schema, CLI and tools. It is fully developed in Rust, allowing for extreme speeds and optimizations which are just not possible with Prisma. 26 | 27 | ## Links 28 | 29 | Check out our API Documentation - [API Documentation](https://turboprisma.js.org/docs) 30 | 31 | Get Started with Turboprisma - [Getting Started](https://turboprisma.js.org/docs/getting-started) -------------------------------------------------------------------------------- /packages/turboprisma/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "turboprisma", 3 | "version": "0.3.0", 4 | "description": "Incredibly fast and performant Prisma runtime that provides an unified access framework, abstractions and new features on top of the Prisma schema, CLI and tools.", 5 | "bin": { 6 | "turboprisma": "./turboprisma_cli" 7 | }, 8 | "homepage": "https://turboprisma.js.org", 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1", 11 | "postinstall": "node postInstall.js" 12 | }, 13 | "keywords": ["turbo", "prisma", "orm", "database", "runtime", "turboprisma", "dmmf", "schema", "parser"], 14 | "author": "DavidHancu", 15 | "license": "Apache-2.0", 16 | "optionalDependencies": { 17 | "@turboprisma/cli-linux-x64": "0.3.0", 18 | "@turboprisma/cli-linux-arm64": "0.3.0", 19 | "@turboprisma/cli-darwin-x64": "0.3.0", 20 | "@turboprisma/cli-darwin-arm64": "0.3.0", 21 | "@turboprisma/cli-windows-x64": "0.3.0", 22 | "@turboprisma/cli-windows-arm64": "0.3.0" 23 | }, 24 | "repository": "https://github.com/DavidHancu/turboprisma", 25 | "bugs": "https://github.com/DavidHancu/turboprisma/issues" 26 | } 27 | -------------------------------------------------------------------------------- /packages/turboprisma/turboprisma_cli: -------------------------------------------------------------------------------- 1 | #/usr/bin/sh -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: 5.4 2 | 3 | specifiers: 4 | semver: ^7.3.8 5 | 6 | devDependencies: 7 | semver: 7.3.8 8 | 9 | packages: 10 | 11 | /lru-cache/6.0.0: 12 | resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} 13 | engines: {node: '>=10'} 14 | dependencies: 15 | yallist: 4.0.0 16 | dev: true 17 | 18 | /semver/7.3.8: 19 | resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==} 20 | engines: {node: '>=10'} 21 | hasBin: true 22 | dependencies: 23 | lru-cache: 6.0.0 24 | dev: true 25 | 26 | /yallist/4.0.0: 27 | resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} 28 | dev: true 29 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - ".github/actions/*" 3 | - "packages/*" 4 | - "!packages/turboprisma" -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2018", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "importHelpers": false, 8 | "noEmitHelpers": false, 9 | "skipLibCheck": true, 10 | "outDir": "./dist", 11 | "baseUrl": "./packages", 12 | }, 13 | "exclude": ["node_modules", "target"] 14 | } --------------------------------------------------------------------------------