1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
use super::Walker;
use crate::{ast, ScalarFieldType, ScalarType};
use diagnostics::Span;
use schema_ast::ast::{WithDocumentation, WithName};
/// A composite type, introduced with the `type` keyword in the schema.
///
/// Example:
///
/// ```prisma
/// type Address {
/// name String
/// streetName String
/// streetNumber Int
/// city String
/// zipCode Int
/// countryCode String
/// }
/// ```
pub type CompositeTypeWalker<'db> = Walker<'db, ast::CompositeTypeId>;
/// A field in a composite type.
pub type CompositeTypeFieldWalker<'db> = Walker<'db, (ast::CompositeTypeId, ast::FieldId)>;
impl<'db> CompositeTypeWalker<'db> {
/// The ID of the composite type node in the AST.
pub fn composite_type_id(self) -> ast::CompositeTypeId {
self.id
}
/// The composite type node in the AST.
pub fn ast_composite_type(self) -> &'db ast::CompositeType {
&self.db.ast()[self.id]
}
/// The name of the composite type in the schema.
pub fn name(self) -> &'db str {
self.ast_composite_type().name()
}
/// Iterator over all the fields of the composite type.
pub fn fields(self) -> impl ExactSizeIterator<Item = CompositeTypeFieldWalker<'db>> + Clone {
self.ast_composite_type()
.iter_fields()
.map(move |(id, _)| self.walk((self.id, id)))
}
}
impl<'db> CompositeTypeFieldWalker<'db> {
fn field(self) -> &'db crate::types::CompositeTypeField {
&self.db.types.composite_type_fields[&self.id]
}
/// The AST node for the field.
pub fn ast_field(self) -> &'db ast::Field {
&self.db.ast[self.id.0][self.id.1]
}
/// The composite type containing the field.
pub fn composite_type(self) -> CompositeTypeWalker<'db> {
self.db.walk(self.id.0)
}
/// The optional documentation string of the field.
pub fn documentation(&self) -> Option<&str> {
self.ast_field().documentation()
}
/// The name contained in the `@map()` attribute of the field, if any.
pub fn mapped_name(self) -> Option<&'db str> {
self.field().mapped_name.map(|id| &self.db[id])
}
/// The ID of the field in the AST.
pub fn field_id(self) -> ast::FieldId {
self.id.1
}
/// The name of the field.
pub fn name(self) -> &'db str {
self.ast_field().name()
}
/// Is the field required, optional or a list?
pub fn arity(self) -> ast::FieldArity {
self.ast_field().arity
}
/// The type of the field, e.g. `String` in `streetName String?`.
pub fn r#type(self) -> ScalarFieldType {
self.field().r#type
}
/// The type of the field in case it is a scalar type (not an enum, not a composite type).
pub fn scalar_type(self) -> Option<ScalarType> {
match self.r#type() {
ScalarFieldType::BuiltInScalar(scalar) => Some(scalar),
_ => None,
}
}
/// The `@default()` AST attribute on the field, if any.
pub fn default_attribute(self) -> Option<&'db ast::Attribute> {
self.field().default.as_ref().map(|d| &self.db.ast[d.default_attribute])
}
/// (attribute scope, native type name, arguments, span)
///
/// For example: `@db.Text` would translate to ("db", "Text", &[], <the span>)
pub fn raw_native_type(self) -> Option<(&'db str, &'db str, &'db [String], Span)> {
let db = self.db;
self.field()
.native_type
.as_ref()
.map(move |(datasource_name, name, args, span)| (&db[*datasource_name], &db[*name], args.as_slice(), *span))
}
/// The value expression in the `@default` attribute.
///
/// ```ignore
/// score Int @default(0)
/// ^
/// ```
pub fn default_value(self) -> Option<&'db ast::Expression> {
let argument_idx = self.field().default.as_ref()?.argument_idx;
let attr = self.default_attribute()?;
Some(&attr.arguments.arguments[argument_idx].value)
}
/// The mapped name of the default value. Always `None` in composite types at the moment.
///
/// ```ignore
/// name String @default("george", map: "name_default_to_george")
/// ^^^^^^^^^^^^^^^^^^^^^^^^
/// ```
pub fn default_mapped_name(self) -> Option<&'db str> {
self.field()
.default
.as_ref()
.and_then(|d| d.mapped_name)
.map(|id| &self.db[id])
}
/// The final database name of the field. See crate docs for explanations on database names.
pub fn database_name(self) -> &'db str {
self.field()
.mapped_name
.map(|id| &self.db[id])
.unwrap_or_else(|| self.name())
}
}