1use std::mem;
2
3use itertools::{Either, Itertools};
4
5use super::{
6 index::Index,
7 sql::Sql,
8 table::{ForeignKey, TableAnnotation},
9};
10use crate::{
11 attribute::AttributeList, changelist::IsCompatible, def_name_impls, derive_is_isomorph_by_id_name, diagnostics::Report, index::{Check, PrimaryKey, UniqueConstraint}, names::{ColumnDefName, ColumnIdent, ColumnKind, DbNativeType, DefName, TypeIdent}, scalar::PropagatedScalarData, uid::{next_uid, OwnUid, RenameMap}, HasIdent, SchemaType, TableColumn
12};
13
14#[derive(Debug)]
15pub enum ColumnAnnotation {
16 Check(Check),
18 Unique(UniqueConstraint),
20 PrimaryKey(PrimaryKey),
22 Index(Index),
24 Default(Sql),
26 InitializeAs(Sql),
39}
40impl ColumnAnnotation {
41 fn as_default(&self) -> Option<&Sql> {
42 match self {
43 Self::Default(s) => Some(s),
44 _ => None,
45 }
46 }
47 fn as_initialize_as(&self) -> Option<&Sql> {
48 match self {
49 Self::InitializeAs(s) => Some(s),
50 _ => None,
51 }
52 }
53 fn propagate_to_table(self, column: ColumnIdent) -> Either<TableAnnotation, Self> {
54 Either::Left(match self {
55 ColumnAnnotation::Check(c) => TableAnnotation::Check(c.propagate_to_table(column)),
56 ColumnAnnotation::Unique(u) => TableAnnotation::Unique(u.propagate_to_table(column)),
57 ColumnAnnotation::PrimaryKey(p) => {
58 TableAnnotation::PrimaryKey(p.propagate_to_table(column))
59 }
60 ColumnAnnotation::Index(i) => TableAnnotation::Index(i.propagate_to_table(column)),
61 _ => return Either::Right(self),
62 })
63 }
64 fn clone_for_mixin(&self) -> Self {
65 self.clone_for_propagate()
66 }
67 fn clone_for_propagate(&self) -> Self {
68 match self {
69 ColumnAnnotation::Check(c) => Self::Check(c.clone_for_propagate()),
70 ColumnAnnotation::Unique(u) => Self::Unique(u.clone_for_propagate()),
71 ColumnAnnotation::PrimaryKey(p) => Self::PrimaryKey(p.clone_for_propagate()),
72 ColumnAnnotation::Index(i) => Self::Index(i.clone_for_propagate()),
73 ColumnAnnotation::Default(d) => Self::Default(d.clone()),
74 ColumnAnnotation::InitializeAs(i) => Self::InitializeAs(i.clone()),
75 }
76 }
77}
78
79#[derive(Debug)]
80pub struct Column {
81 uid: OwnUid,
82 name: ColumnDefName,
83 pub docs: Vec<String>,
84 pub attrs: AttributeList,
85 pub nullable: bool,
86 pub ty: TypeIdent,
87 pub annotations: Vec<ColumnAnnotation>,
88 pub foreign_key: Option<PartialForeignKey>,
89}
90def_name_impls!(Column, ColumnKind);
91derive_is_isomorph_by_id_name!(Column);
92impl Column {
93 pub fn new(
94 name: ColumnDefName,
95 docs: Vec<String>,
96 attrs: AttributeList,
97 nullable: bool,
98 ty: TypeIdent,
99 annotations: Vec<ColumnAnnotation>,
100 foreign_key: Option<PartialForeignKey>,
101 ) -> Self {
102 Self {
103 uid: next_uid(),
104 attrs,
105 name,
106 docs,
107 nullable,
108 ty,
109 annotations,
110 foreign_key,
111 }
112 }
113}
114impl IsCompatible for Column {
115 fn is_compatible(&self, _new: &Self, _rn: &RenameMap, a: &mut Report, b: &mut Report) -> bool {
116 true
117 }
118}
119
120#[derive(Debug)]
121pub struct PartialForeignKey {
122 pub fk: ForeignKey,
123}
124impl PartialForeignKey {
125 fn clone_for_mixin(&self) -> Self {
126 Self {
127 fk: self.fk.clone_for_mixin(),
128 }
129 }
130}
131
132impl Column {
133 pub(crate) fn propagate_scalar_data(
134 &mut self,
135 scalar: TypeIdent,
136 propagated: &PropagatedScalarData,
137 ) {
138 if self.ty == scalar {
139 self.annotations.extend(
140 propagated
141 .annotations
142 .iter()
143 .map(|v| v.clone_for_propagate()),
144 );
145 }
146 }
147 pub fn propagate_annotations(&mut self) -> Vec<TableAnnotation> {
148 let (annotations, retained) = mem::take(&mut self.annotations)
149 .into_iter()
150 .partition_map(|a| a.propagate_to_table(self.id()));
151 self.annotations = retained;
152 annotations
153 }
154 pub fn propagate_foreign_key(&mut self) -> Option<ForeignKey> {
155 let mut fk = self.foreign_key.take()?;
156 fk.fk.source_fields = Some(vec![self.id()]);
157 Some(fk.fk)
158 }
159
160 pub fn clone_for_mixin(&self) -> Column {
161 Column::new(
162 DefName::unchecked_new(
163 self.name.code,
164 self.name.db.clone(),
166 ),
167 self.docs.clone(),
168 self.attrs.clone(),
169 self.nullable,
170 self.ty,
171 self.annotations
172 .iter()
173 .map(|a| a.clone_for_mixin())
174 .collect(),
175 self.foreign_key.as_ref().map(|fk| fk.clone_for_mixin()),
176 )
177 }
178}
179
180impl<'a> TableColumn<'a> {
181 pub fn db_type(&self, rn: &RenameMap, report: &mut Report) -> DbNativeType {
182 self.table.schema.native_type(&self.ty, rn, report)
183 }
184 pub fn ty(&'a self) -> SchemaType<'a> {
185 self.table.schema.schema_ty(self.ty)
186 }
187 pub fn default(&self) -> Option<&Sql> {
191 self.annotations
192 .iter()
193 .filter_map(|v| v.as_default())
194 .at_most_one()
195 .unwrap()
196 }
197 pub fn initialize_as(&self) -> Option<&Sql> {
198 self.annotations
199 .iter()
200 .filter_map(|v| v.as_initialize_as())
201 .at_most_one()
202 .unwrap()
203 }
204 pub fn is_pk_part(&self) -> bool {
205 let Some(pk) = self.table.pk() else {
206 return false;
207 };
208 pk.columns.contains(&self.id())
209 }
210 pub fn has_default(&self) -> bool {
211 self.default().is_some() || self.ty().has_default()
212 }
213 pub fn is_pk_full(&self) -> bool {
214 let Some(pk) = self.table.pk() else {
215 return false;
216 };
217 pk.columns == [self.id()]
218 }
219}