Skip to content

Commit

Permalink
Merge branch 'feat/assert-in-driver-adapters' of github.com:prisma/pr…
Browse files Browse the repository at this point in the history
…isma-engines into feat/assert-in-driver-adapters
  • Loading branch information
jkomyno committed Sep 11, 2023
2 parents e5ec12a + cc4627c commit 9a9e7a7
Show file tree
Hide file tree
Showing 9 changed files with 152 additions and 36 deletions.
10 changes: 10 additions & 0 deletions prisma-fmt/src/code_actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,16 @@ pub(crate) fn available_actions(schema: String, params: CodeActionParams) -> Vec
complete_relation.referencing_field(),
);
}

if validated_schema.relation_mode().uses_foreign_keys() {
relation_mode::replace_set_default_mysql(
&mut actions,
&params,
validated_schema.db.source(),
complete_relation,
config,
)
}
}
}

Expand Down
50 changes: 49 additions & 1 deletion prisma-fmt/src/code_actions/relation_mode.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use lsp_types::{CodeAction, CodeActionKind, CodeActionOrCommand};
use psl::schema_ast::ast::SourceConfig;
use psl::{parser_database::walkers::CompleteInlineRelationWalker, schema_ast::ast::SourceConfig, Configuration};

pub(crate) fn edit_referential_integrity(
actions: &mut Vec<CodeActionOrCommand>,
Expand Down Expand Up @@ -35,3 +35,51 @@ pub(crate) fn edit_referential_integrity(

actions.push(CodeActionOrCommand::CodeAction(action))
}

pub(crate) fn replace_set_default_mysql(
actions: &mut Vec<CodeActionOrCommand>,
params: &lsp_types::CodeActionParams,
schema: &str,
relation: CompleteInlineRelationWalker<'_>,
config: &Configuration,
) {
let datasource = match config.datasources.first() {
Some(ds) => ds,
None => return,
};

if datasource.active_connector.provider_name() != "mysql" {
return;
}

let span = match relation.on_update_span() {
Some(span) => span,
None => return,
};

let span_diagnostics = match super::diagnostics_for_span(schema, &params.context.diagnostics, span) {
Some(sd) => sd,
None => return,
};

let diagnostics = match
super::filter_diagnostics(
span_diagnostics,
"MySQL does not actually support the `SetDefault` referential action, so using it may result in unexpected errors.") {
Some(value) => value,
None => return,
};

let edit = super::create_text_edit(schema, "NoAction".to_owned(), false, span, params);

let action = CodeAction {
title: r#"Replace SetDefault with NoAction"#.to_owned(),

kind: Some(CodeActionKind::QUICKFIX),
edit: Some(edit),
diagnostics: Some(diagnostics),
..Default::default()
};

actions.push(CodeActionOrCommand::CodeAction(action))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
[
{
"title": "Replace SetDefault with NoAction",
"kind": "quickfix",
"diagnostics": [
{
"range": {
"start": {
"line": 14,
"character": 62
},
"end": {
"line": 14,
"character": 82
}
},
"severity": 2,
"message": "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 "
}
],
"edit": {
"changes": {
"file:///path/to/schema.prisma": [
{
"range": {
"start": {
"line": 14,
"character": 72
},
"end": {
"line": 14,
"character": 82
}
},
"newText": "NoAction"
}
]
}
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
generator client {
provider = "prisma-client-js"
}

datasource db {
provider = "mysql"
url = env("DATABASE_URL")
relationMode = "foreignKeys"
}

/// multi line
/// commennttt
model Foo {
id Int @id
bar Bar @relation(fields: [bar_id], references: [id], onUpdate: SetDefault)
bar_id Int @unique
t Test
}

model Bar {
id Int @id
foo Foo?
}

// This is a test enum.
enum Test {
TestUno
TestDue
}
1 change: 1 addition & 0 deletions prisma-fmt/tests/code_actions/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ scenarios! {
one_to_one_referencing_side_misses_unique_compound_field_indentation_four_spaces
relation_mode_prisma_missing_index
relation_mode_referential_integrity
relation_mode_mysql_foreign_keys_set_default
multi_schema_one_model
multi_schema_one_model_one_enum
multi_schema_two_models
Expand Down
5 changes: 5 additions & 0 deletions psl/parser-database/src/walkers/relation/inline/complete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::{
walkers::{ModelWalker, RelationFieldId, RelationFieldWalker, ScalarFieldWalker},
ParserDatabase, ReferentialAction,
};
use diagnostics::Span;
use schema_ast::ast;

/// Represents a relation that has fields and references defined in one of the
Expand Down Expand Up @@ -65,6 +66,10 @@ impl<'db> CompleteInlineRelationWalker<'db> {
.unwrap_or(Cascade)
}

pub fn on_update_span(self) -> Option<Span> {
self.referencing_field().attributes().on_update.map(|(_, span)| span)
}

/// Prisma allows setting the relation field as optional, even if one of the
/// underlying scalar fields is required. For the purpose of referential
/// actions, we count the relation field required if any of the underlying
Expand Down
37 changes: 11 additions & 26 deletions query-engine/connectors/sql-query-connector/src/database/js.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,40 +11,25 @@ use quaint::{
connector::{IsolationLevel, Transaction},
prelude::{Queryable as QuaintQueryable, *},
};
use std::{
collections::{hash_map::Entry, HashMap},
sync::{Arc, Mutex},
};
use std::sync::{Arc, Mutex};

/// Registry is the type for the global registry of driver adapters.
type Registry = HashMap<String, DriverAdapter>;
static ACTIVE_DRIVER_ADAPTER: Lazy<Mutex<Option<DriverAdapter>>> = Lazy::new(|| Mutex::new(None));

/// REGISTRY is the global registry of Driver Adapters.
static REGISTRY: Lazy<Mutex<Registry>> = Lazy::new(|| Mutex::new(HashMap::new()));
fn active_driver_adapter(provider: &str) -> connector::Result<DriverAdapter> {
let lock = ACTIVE_DRIVER_ADAPTER.lock().unwrap();

fn registered_driver_adapter(provider: &str) -> connector::Result<DriverAdapter> {
let lock = REGISTRY.lock().unwrap();
lock.get(provider)
lock.as_ref()
.map(|conn_ref| conn_ref.to_owned())
.ok_or(ConnectorError::from_kind(ErrorKind::UnsupportedConnector(format!(
"A driver adapter for {} was not registered",
provider
))))
.map(|conn_ref| conn_ref.to_owned())
}

pub fn register_driver_adapter(provider: &str, connector: Arc<dyn TransactionCapable>) -> Result<(), String> {
let mut lock = REGISTRY.lock().unwrap();
let entry = lock.entry(provider.to_string());
match entry {
Entry::Occupied(_) => Err(format!(
"A driver adapter for {} was already registered, and cannot be overridden.",
provider
)),
Entry::Vacant(v) => {
v.insert(DriverAdapter { connector });
Ok(())
}
}
pub fn activate_driver_adapter(connector: Arc<dyn TransactionCapable>) {
let mut lock = ACTIVE_DRIVER_ADAPTER.lock().unwrap();

*lock = Some(DriverAdapter { connector });
}

pub struct Js {
Expand All @@ -69,7 +54,7 @@ impl FromSource for Js {
url: &str,
features: psl::PreviewFeatures,
) -> connector_interface::Result<Js> {
let connector = registered_driver_adapter(source.active_provider)?;
let connector = active_driver_adapter(source.active_provider)?;
let connection_info = get_connection_info(url)?;

Ok(Js {
Expand Down
2 changes: 1 addition & 1 deletion query-engine/connectors/sql-query-connector/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use self::{column_metadata::*, context::Context, filter_conversion::*, query_ext
use quaint::prelude::Queryable;

#[cfg(feature = "driver-adapters")]
pub use database::{register_driver_adapter, Js};
pub use database::{activate_driver_adapter, Js};
pub use database::{FromSource, Mssql, Mysql, PostgreSql, Sqlite};
pub use error::SqlError;

Expand Down
13 changes: 5 additions & 8 deletions query-engine/query-engine-node-api/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,15 +183,12 @@ impl QueryEngine {
#[cfg(feature = "driver-adapters")]
if let Some(driver) = maybe_driver {
let js_queryable = driver_adapters::from_napi(driver);
let provider_name = schema.connector.provider_name();

match sql_connector::register_driver_adapter(provider_name, Arc::new(js_queryable)) {
Ok(_) => {
connector_mode = ConnectorMode::Js;
tracing::info!("Registered driver adapter for {provider_name}.")
}
Err(err) => tracing::error!("Failed to register driver adapter for {provider_name}. {err}"),
}
sql_connector::activate_driver_adapter(Arc::new(js_queryable));
connector_mode = ConnectorMode::Js;

let provider_name = schema.connector.provider_name();
tracing::info!("Registered driver adapter for {provider_name}.");
}
}

Expand Down

0 comments on commit 9a9e7a7

Please sign in to comment.