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
use crate::prelude::*;
use psl::{parser_database::walkers, schema_ast::ast};

pub type Model = crate::Zipper<ast::ModelId>;

impl Model {
    pub fn name(&self) -> &str {
        self.walker().name()
    }

    /// Returns the set of fields to be used as the primary identifier for a record of that model.
    /// The identifier is nothing but an internal convention to have an anchor point for querying, or in other words,
    /// the identifier is not to be mistaken for a stable, external identifier, but has to be understood as
    /// implementation detail that is used to reason over a fixed set of fields.
    pub fn primary_identifier(&self) -> FieldSelection {
        let fields: Vec<_> = self
            .walker()
            .required_unique_criterias()
            .next()
            .unwrap()
            .fields()
            .map(|f| {
                self.dm
                    .clone()
                    .zip(ScalarFieldId::InModel(f.as_scalar_field().unwrap().id))
            })
            .collect();

        FieldSelection::from(fields)
    }

    pub fn fields(&self) -> Fields<'_> {
        Fields::new(self)
    }

    pub fn supports_create_operation(&self) -> bool {
        let has_unsupported_field = self
            .walker()
            .scalar_fields()
            .any(|sf| sf.ast_field().arity.is_required() && sf.is_unsupported() && sf.default_value().is_none());

        !has_unsupported_field
    }

    /// The name of the model in the database
    /// For a sql database this will be the Table name for this model
    pub fn db_name(&self) -> &str {
        self.walker().database_name()
    }

    pub fn db_name_opt(&self) -> Option<&str> {
        self.walker().mapped_name()
    }

    pub fn unique_indexes(&self) -> impl Iterator<Item = walkers::IndexWalker<'_>> {
        self.walker()
            .indexes()
            .filter(|idx| idx.is_unique())
            .filter(|index| !index.fields().any(|f| f.is_unsupported()))
    }
}

impl std::fmt::Debug for Model {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_tuple("Model").field(&self.name()).finish()
    }
}