diff --git a/psl/diagnostics/src/error.rs b/psl/diagnostics/src/error.rs index 7d3782ccc86..8cac9c67918 100644 --- a/psl/diagnostics/src/error.rs +++ b/psl/diagnostics/src/error.rs @@ -29,6 +29,13 @@ impl DatamodelError { ) } + pub fn new_named_env_val(span: Span) -> Self { + Self::new( + "The env function expects a singular, unnamed, string argument.".to_owned(), + span, + ) + } + pub fn new_argument_not_found_error(argument_name: &str, span: Span) -> DatamodelError { Self::new(format!("Argument \"{argument_name}\" is missing."), span) } diff --git a/psl/diagnostics/src/warning.rs b/psl/diagnostics/src/warning.rs index ba48e6bbee6..bf6b9b8116d 100644 --- a/psl/diagnostics/src/warning.rs +++ b/psl/diagnostics/src/warning.rs @@ -44,6 +44,11 @@ impl DatamodelWarning { Self::new(message, span) } + pub fn new_named_env_val(span: Span) -> Self { + let message = "The env function doesn't expect named arguments".to_owned(); + Self::new(message, span) + } + pub fn new_field_validation(message: &str, model: &str, field: &str, span: Span) -> DatamodelWarning { let msg = format!( "Warning validating field `{}` in {} `{}`: {}", diff --git a/psl/psl-core/src/configuration/env_vars.rs b/psl/psl-core/src/configuration/env_vars.rs index 81a9042d779..ac7359d7001 100644 --- a/psl/psl-core/src/configuration/env_vars.rs +++ b/psl/psl-core/src/configuration/env_vars.rs @@ -1,5 +1,6 @@ use crate::parser_database::{ast, coerce}; -use diagnostics::{DatamodelError, Diagnostics}; +use diagnostics::{DatamodelError, DatamodelWarning, Diagnostics}; +use schema_ast::ast::WithSpan; use serde::Serialize; /// Either an env var or a string literal. @@ -15,16 +16,8 @@ pub struct StringFromEnvVar { impl StringFromEnvVar { pub(crate) fn coerce(expr: &ast::Expression, diagnostics: &mut Diagnostics) -> Option { match expr { - ast::Expression::Function(name, _, _) if name == "env" => { - let mut errs = Diagnostics::new(); - match EnvFunction::from_ast(expr, &mut errs) { - Some(env_function) => Some(StringFromEnvVar::new_from_env_var(env_function.var_name().to_owned())), - None => { - diagnostics.push_error(errs.errors()[0].clone()); - None - } - } - } + ast::Expression::Function(name, _, _) if name == "env" => EnvFunction::from_ast(expr, diagnostics) + .map(|env_function| StringFromEnvVar::new_from_env_var(env_function.var_name().to_owned())), ast::Expression::StringValue(value, _) => Some(StringFromEnvVar::new_literal(value.clone())), _ => { diagnostics.push_error(DatamodelError::new_type_mismatch_error( @@ -71,6 +64,16 @@ impl EnvFunction { fn from_ast(expr: &ast::Expression, diagnostics: &mut Diagnostics) -> Option { let args = if let ast::Expression::Function(name, args, _) = &expr { if name == "env" { + args.arguments + .iter() + .filter(|arg| !arg.is_unnamed()) + .for_each(|arg| diagnostics.push_warning(DatamodelWarning::new_named_env_val(arg.span()))); + + if args.arguments.is_empty() && !args.empty_arguments.is_empty() { + diagnostics.push_error(DatamodelError::new_named_env_val(expr.span())); + return None; + } + args } else { diagnostics.push_error(DatamodelError::new_functional_evaluation_error( @@ -87,7 +90,15 @@ impl EnvFunction { return None; }; - if args.arguments.len() != 1 { + if args.arguments.len() + args.empty_arguments.len() != 1 { + diagnostics.push_error(DatamodelError::new_functional_evaluation_error( + "Exactly one string parameter must be passed to the env function.", + expr.span(), + )); + return None; + } + + if args.trailing_comma.is_some() { diagnostics.push_error(DatamodelError::new_functional_evaluation_error( "Exactly one string parameter must be passed to the env function.", expr.span(), diff --git a/psl/psl/tests/validation/datasource/url_empty_named_arg.prisma b/psl/psl/tests/validation/datasource/url_empty_named_arg.prisma new file mode 100644 index 00000000000..99276c437c0 --- /dev/null +++ b/psl/psl/tests/validation/datasource/url_empty_named_arg.prisma @@ -0,0 +1,11 @@ +datasource testds { + provider = "mysql" + url = env(named: ) +} + +// error: The env function expects a singular, unnamed, string argument. +// --> schema.prisma:3 +//  |  +//  2 |  provider = "mysql" +//  3 |  url = env(named: ) +//  |  diff --git a/psl/psl/tests/validation/datasource/url_named_arg.prisma b/psl/psl/tests/validation/datasource/url_named_arg.prisma new file mode 100644 index 00000000000..600604790b4 --- /dev/null +++ b/psl/psl/tests/validation/datasource/url_named_arg.prisma @@ -0,0 +1,11 @@ +datasource testds { + provider = "mysql" + url = env(named: "DATABASE_URL") +} + +// warning: The env function doesn't expect named arguments +// --> schema.prisma:3 +//  |  +//  2 |  provider = "mysql" +//  3 |  url = env(named: "DATABASE_URL") +//  |