Skip to content

Commit

Permalink
qe: start introducing typed identifiers in relations (#3672)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomhoule authored Feb 7, 2023
1 parent ca7fcef commit d026664
Show file tree
Hide file tree
Showing 17 changed files with 108 additions and 124 deletions.
6 changes: 3 additions & 3 deletions psl/psl/tests/attributes/relations/relations_new.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@ fn relation_happy_path() {

let schema = parse(dml);
let user_model = schema.assert_has_model("User");
let post_model = schema.assert_has_model("Post");
user_model
.assert_has_relation_field("posts")
.assert_arity(&dml::FieldArity::List)
.assert_relation_to("Post")
.assert_relation_to(post_model.id)
.assert_relation_base_fields(&[])
.assert_relation_referenced_fields(&[]);

let post_model = schema.assert_has_model("Post");
post_model
.assert_has_relation_field("user")
.assert_arity(&dml::FieldArity::Required)
.assert_relation_to("User")
.assert_relation_to(user_model.id)
.assert_relation_base_fields(&["userId"])
.assert_relation_referenced_fields(&["id"]);
}
Expand Down
42 changes: 25 additions & 17 deletions psl/psl/tests/attributes/relations/relations_positive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ fn settings_must_be_deteced() {

let schema = parse(dml);

schema
.assert_has_model("Todo")
let todo_model = schema.assert_has_model("Todo");
todo_model
.assert_has_relation_field("parent_todo")
.assert_relation_to("Todo")
.assert_relation_to(todo_model.id)
.assert_relation_referenced_fields(&["id"])
.assert_arity(&dml::FieldArity::Optional);
}
Expand All @@ -68,19 +68,21 @@ fn resolve_relation() {

let schema = parse(dml);
let user_model = schema.assert_has_model("User");
let post_model = schema.assert_has_model("Post");
user_model
.assert_has_scalar_field("firstName")
.assert_base_type(&ScalarType::String);
user_model
.assert_has_relation_field("posts")
.assert_relation_to("Post")
.assert_relation_to(post_model.id)
.assert_arity(&dml::FieldArity::List);

let post_model = schema.assert_has_model("Post");
post_model
.assert_has_scalar_field("text")
.assert_base_type(&ScalarType::String);
post_model.assert_has_relation_field("user").assert_relation_to("User");
post_model
.assert_has_relation_field("user")
.assert_relation_to(user_model.id);
}

#[test]
Expand All @@ -102,10 +104,11 @@ fn resolve_related_field() {

let schema = parse(dml);

let user_model = schema.assert_has_model("User");
let post_model = schema.assert_has_model("Post");
post_model
.assert_has_relation_field("user")
.assert_relation_to("User")
.assert_relation_to(user_model.id)
.assert_relation_referenced_fields(&["firstName"]);
}

Expand All @@ -132,10 +135,11 @@ fn resolve_related_fields() {

let schema = parse(dml);

let user_model = schema.assert_has_model("User");
let post_model = schema.assert_has_model("Post");
post_model
.assert_has_relation_field("user")
.assert_relation_to("User")
.assert_relation_to(user_model.id)
.assert_relation_base_fields(&["authorFirstName", "authorLastName"])
.assert_relation_referenced_fields(&["firstName", "lastName"]);
}
Expand All @@ -162,31 +166,31 @@ fn allow_multiple_relations() {

let schema = parse(dml);
let user_model = schema.assert_has_model("User");
let post_model = schema.assert_has_model("Post");
user_model
.assert_field_count(3)
.assert_has_relation_field("posts")
.assert_relation_to("Post")
.assert_relation_to(post_model.id)
.assert_arity(&dml::FieldArity::List)
.assert_relation_name("PostToUser");
user_model
.assert_has_relation_field("more_posts")
.assert_relation_to("Post")
.assert_relation_to(post_model.id)
.assert_arity(&dml::FieldArity::List)
.assert_relation_name("more_posts");

let post_model = schema.assert_has_model("Post");
post_model
.assert_field_count(6)
.assert_has_scalar_field("text")
.assert_base_type(&ScalarType::String);
post_model
.assert_has_relation_field("user")
.assert_relation_to("User")
.assert_relation_to(user_model.id)
.assert_arity(&dml::FieldArity::Required)
.assert_relation_name("PostToUser");
post_model
.assert_has_relation_field("posting_user")
.assert_relation_to("User")
.assert_relation_to(user_model.id)
.assert_arity(&dml::FieldArity::Required)
.assert_relation_name("more_posts");
}
Expand All @@ -209,14 +213,18 @@ fn allow_complicated_self_relations() {

let schema = parse(dml);
let user_model = schema.assert_has_model("User");
user_model.assert_has_relation_field("son").assert_relation_to("User");
user_model
.assert_has_relation_field("son")
.assert_relation_to(user_model.id);
user_model
.assert_has_relation_field("father")
.assert_relation_to("User");
.assert_relation_to(user_model.id);
user_model
.assert_has_relation_field("husband")
.assert_relation_to("User");
user_model.assert_has_relation_field("wife").assert_relation_to("User");
.assert_relation_to(user_model.id);
user_model
.assert_has_relation_field("wife")
.assert_relation_to(user_model.id);
}

#[test]
Expand Down
3 changes: 2 additions & 1 deletion psl/psl/tests/base/array_sugar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ fn should_treat_single_values_as_arrays_of_length_one() {

let schema = parse(dml);

let user_model = schema.assert_has_model("User");
let post_model = schema.assert_has_model("Post");
post_model
.assert_has_relation_field("user")
.assert_relation_to("User")
.assert_relation_to(user_model.id)
.assert_relation_referenced_fields(&["id"]);
}
6 changes: 3 additions & 3 deletions psl/psl/tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pub(crate) use asserts::*;
pub use dml::*;
pub use expect_test::expect;

use psl::{diagnostics::*, Configuration, StringFromEnvVar};
use psl::{diagnostics::*, schema_ast::ast, Configuration, StringFromEnvVar};

pub(crate) fn reformat(input: &str) -> String {
psl::reformat(input, 2).unwrap_or_else(|| input.to_owned())
Expand Down Expand Up @@ -39,7 +39,7 @@ pub(crate) trait CompositeTypeFieldAsserts {

pub(crate) trait RelationFieldAsserts {
fn assert_relation_name(&self, t: &str) -> &Self;
fn assert_relation_to(&self, t: &str) -> &Self;
fn assert_relation_to(&self, t: ast::ModelId) -> &Self;
fn assert_relation_delete_strategy(&self, t: dml::ReferentialAction) -> &Self;
fn assert_relation_update_strategy(&self, t: dml::ReferentialAction) -> &Self;
fn assert_relation_referenced_fields(&self, t: &[&str]) -> &Self;
Expand Down Expand Up @@ -191,7 +191,7 @@ impl RelationFieldAsserts for dml::RelationField {
self
}

fn assert_relation_to(&self, t: &str) -> &Self {
fn assert_relation_to(&self, t: ast::ModelId) -> &Self {
assert_eq!(self.relation_info.referenced_model, t);
self
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,7 @@ impl AsTable for Relation {
}
RelationLinkManifestation::Inline(ref m) => self
.internal_data_model()
.find_model(&m.in_table_of_model_name)
.unwrap()
.find_model_by_id(m.in_table_of_model)
.as_table(ctx),
}
}
Expand Down
31 changes: 6 additions & 25 deletions query-engine/dml/src/datamodel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,8 @@ use crate::composite_type::CompositeType;
use crate::field::RelationField;
use crate::model::Model;
use crate::relation_info::RelationInfo;
use psl_core::schema_ast::ast;

/// Entities in the datamodel can be flagged as `is_commented_out`. This lets the renderer
/// know that introspection encountered unsupported names or features and these are supposed
/// to be rendered as comments. Since the parser will not set these flags when reading a schema
/// string, only introspection and the lowering of the datamodel to the ast care about these flags.
/// The FieldType: Unsupported behaves in the same way.
/// Both of these are never converted into the internal datamodel.
#[derive(Debug, Default)]
pub struct Datamodel {
pub models: Vec<Model>,
Expand All @@ -31,6 +26,10 @@ impl Datamodel {
self.models().find(|model| model.name == name)
}

pub fn find_model_by_id(&self, id: ast::ModelId) -> Option<&Model> {
self.models().find(|m| m.id == id)
}

/// Finds a composite type by name.
pub fn find_composite_type(&self, name: &str) -> Option<&CompositeType> {
self.composite_types().find(|composite| composite.name == name)
Expand All @@ -43,11 +42,6 @@ impl Datamodel {
.find(|model| model.database_name.as_deref() == Some(db_name))
}

/// Finds parent model for a field reference.
pub fn find_model_by_relation_field_ref(&self, field: &RelationField) -> Option<&Model> {
self.find_model(&self.find_related_field_bang(field).1.relation_info.referenced_model)
}

/// Finds a model by name and returns a mutable reference.
pub fn find_model_mut(&mut self, name: &str) -> &mut Model {
self.models
Expand All @@ -56,22 +50,9 @@ impl Datamodel {
.expect("We assume an internally valid datamodel before mutating.")
}

/// Returns (model_name, field_name) for all relation fields pointing to a specific model.
pub fn find_relation_fields_for_model(&mut self, model_name: &str) -> Vec<(String, String)> {
let mut fields = vec![];
for model in self.models() {
for field in model.relation_fields() {
if field.relation_info.referenced_model == model_name {
fields.push((model.name.clone(), field.name.clone()))
}
}
}
fields
}

/// Finds a relation field related to a relation info. Returns a tuple (index_of_relation_field_in_model, relation_field).
pub fn find_related_field_for_info(&self, info: &RelationInfo, exclude: &str) -> Option<(usize, &RelationField)> {
self.find_model(&info.referenced_model)
self.find_model_by_id(info.referenced_model)
.expect("The model referred to by a RelationInfo should always exist.")
.fields
.iter()
Expand Down
20 changes: 0 additions & 20 deletions query-engine/dml/src/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,10 +331,6 @@ impl RelationField {
self.emulates_referential_actions = Some(value);
}

pub fn points_to_model(&self, name: &str) -> bool {
self.relation_info.referenced_model == name
}

pub fn is_required(&self) -> bool {
self.arity.is_required()
}
Expand All @@ -343,14 +339,6 @@ impl RelationField {
self.arity.is_list()
}

pub fn is_singular(&self) -> bool {
!self.is_list()
}

pub fn is_optional(&self) -> bool {
self.arity.is_optional()
}

pub fn default_on_delete_action(&self) -> ReferentialAction {
use ReferentialAction::*;

Expand Down Expand Up @@ -446,14 +434,6 @@ impl ScalarField {
self.arity.is_required()
}

pub fn is_list(&self) -> bool {
self.arity.is_list()
}

pub fn is_singular(&self) -> bool {
!self.is_list()
}

pub fn is_optional(&self) -> bool {
self.arity.is_optional()
}
Expand Down
8 changes: 4 additions & 4 deletions query-engine/dml/src/lift.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ impl<'a> LiftAstToDml<'a> {

let referenced_model = relation.referenced_model();

let relation_info = RelationInfo::new(referenced_model.name());
let relation_info = RelationInfo::new(referenced_model.id);

let forward_field_walker = relation.forward_relation_field().unwrap();
// Construct a relation field in the DML for an existing relation field in the source.
Expand Down Expand Up @@ -181,7 +181,7 @@ impl<'a> LiftAstToDml<'a> {

// Back field
{
let relation_info = RelationInfo::new(relation.referencing_model().name());
let relation_info = RelationInfo::new(relation.referencing_model().id);
let model = schema.find_model_mut(relation.referenced_model().name());

let mut field = if let Some(relation_field) = relation.back_relation_field() {
Expand Down Expand Up @@ -227,7 +227,7 @@ impl<'a> LiftAstToDml<'a> {
for relation_field in [relation.field_a(), relation.field_b()] {
let ast_field = relation_field.ast_field();
let arity = ast_field.arity;
let relation_info = RelationInfo::new(relation_field.related_model().name());
let relation_info = RelationInfo::new(relation_field.related_model().id);
let referential_arity = relation_field.referential_arity();
let mut field = RelationField::new(
relation_field.id,
Expand Down Expand Up @@ -262,7 +262,7 @@ impl<'a> LiftAstToDml<'a> {
for relation_field in [relation.field_a(), relation.field_b()] {
let ast_field = relation_field.ast_field();
let arity = ast_field.arity;
let relation_info = RelationInfo::new(relation_field.related_model().name());
let relation_info = RelationInfo::new(relation_field.related_model().id);
let referential_arity = relation_field.referential_arity();

let mut field = RelationField::new(
Expand Down
8 changes: 4 additions & 4 deletions query-engine/dml/src/relation_info.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use psl_core::parser_database as db;
use psl_core::{parser_database as db, schema_ast::ast};

/// Holds information about a relation field.
#[derive(Debug, PartialEq, Clone)]
pub struct RelationInfo {
/// The target model of the relation.
pub referenced_model: String,
pub referenced_model: ast::ModelId,
/// The fields forming the relation.
pub fields: Vec<String>,
/// The target field of the relation a.k.a. `references`
Expand All @@ -24,9 +24,9 @@ pub struct RelationInfo {
impl RelationInfo {
/// Creates a new relation info for the
/// given target model.
pub fn new(model: &str) -> RelationInfo {
pub fn new(referenced_model: ast::ModelId) -> RelationInfo {
RelationInfo {
referenced_model: String::from(model),
referenced_model,
fields: Vec::new(),
references: Vec::new(),
name: String::new(),
Expand Down
Loading

0 comments on commit d026664

Please sign in to comment.