immigrant_schema/
index.rs

1use super::sql::Sql;
2use crate::{
3	db_name_impls, diagnostics::Report, ids::DbIdent, names::{ColumnIdent, ConstraintKind, DbColumn, DbNativeType, FieldIdent, IndexKind}, uid::{next_uid, OwnUid, RenameMap, Uid}, TableIndex
4};
5
6/// Can appear on columns, scalars, and tables.
7///
8/// Checks with the same name are merged using sql AND operator.
9#[derive(Debug)]
10pub struct Check {
11	uid: OwnUid,
12	name: Option<DbIdent<ConstraintKind>>,
13	pub check: Sql,
14}
15db_name_impls!(Check, ConstraintKind);
16impl Check {
17	pub fn new(name: Option<DbIdent<ConstraintKind>>, check: Sql) -> Self {
18		Self {
19			uid: next_uid(),
20			name,
21			check,
22		}
23	}
24	pub fn propagate_to_table(mut self, column: ColumnIdent) -> Self {
25		self.check.replace_placeholder(Sql::Ident(column));
26		self
27	}
28	pub fn propagate_to_composite(mut self, field: FieldIdent) -> Self {
29		self.check
30			.replace_placeholder(Sql::GetField(Box::new(Sql::Placeholder), field));
31		self
32	}
33	pub fn clone_for_propagate(&self) -> Self {
34		Check {
35			uid: next_uid(),
36			name: self.name.clone(),
37			check: self.check.clone(),
38		}
39	}
40}
41
42/// Can appear on columns, scalars, and tables.
43///
44/// Constraints with the same name are merged, unifying columns.
45/// When appears on a scalar - always inlined to column.
46#[derive(Debug)]
47pub struct UniqueConstraint {
48	uid: OwnUid,
49	name: Option<DbIdent<ConstraintKind>>,
50	pub columns: Vec<ColumnIdent>,
51}
52db_name_impls!(UniqueConstraint, ConstraintKind);
53impl UniqueConstraint {
54	pub fn new(name: Option<DbIdent<ConstraintKind>>, columns: Vec<ColumnIdent>) -> Self {
55		Self {
56			uid: next_uid(),
57			name,
58			columns,
59		}
60	}
61	pub fn propagate_to_table(mut self, column: ColumnIdent) -> Self {
62		self.columns.insert(0, column);
63		self
64	}
65	pub fn clone_for_propagate(&self) -> Self {
66		Self {
67			uid: next_uid(),
68			name: self.name.clone(),
69			columns: self.columns.clone(),
70		}
71	}
72}
73
74/// Can appear on columns, scalars, and tables.
75///
76/// Only tables can define name for primary key, in other cases it will raise a validation error.
77/// Always merged, if there is a name conflict - raises a validation error.
78/// When appears on a scalar - always inlined to column.
79#[derive(Debug)]
80pub struct PrimaryKey {
81	uid: OwnUid,
82	name: Option<DbIdent<ConstraintKind>>,
83	pub columns: Vec<ColumnIdent>,
84}
85db_name_impls!(PrimaryKey, ConstraintKind);
86impl PrimaryKey {
87	pub fn new(name: Option<DbIdent<ConstraintKind>>, columns: Vec<ColumnIdent>) -> Self {
88		Self {
89			uid: next_uid(),
90			name,
91			columns,
92		}
93	}
94	pub fn propagate_to_table(mut self, column: ColumnIdent) -> Self {
95		self.columns.insert(0, column);
96		self
97	}
98	pub fn clone_for_propagate(&self) -> Self {
99		Self {
100			uid: next_uid(),
101			name: self.name.clone(),
102			columns: self.columns.clone(),
103		}
104	}
105}
106
107#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
108pub struct Using(pub String);
109#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
110pub struct OpClass(pub String);
111#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
112pub struct With(pub String);
113
114/// Can appear on columns, scalars, and tables.
115///
116/// Indexed with the same name are merged, if one index is marked as unique, and other isn't - raises a validation error.
117// TODO: Index kind? BTREE/etc
118#[derive(Debug)]
119pub struct Index {
120	uid: OwnUid,
121	name: Option<DbIdent<IndexKind>>,
122	pub unique: bool,
123	fields: Vec<(ColumnIdent, Option<OpClass>)>,
124	pub using: Option<Using>,
125	// FIXME: Should only exist when Index is defined on field, this opclass is applied to the field itself, not to the index
126	pub default_opclass: Option<OpClass>,
127	pub with: Option<With>,
128}
129db_name_impls!(Index, IndexKind);
130impl Index {
131	pub fn new(
132		name: Option<DbIdent<IndexKind>>,
133		unique: bool,
134		fields: Vec<(ColumnIdent, Option<OpClass>)>,
135		using: Option<Using>,
136		default_opclass: Option<OpClass>,
137		with: Option<With>,
138	) -> Self {
139		Self {
140			uid: next_uid(),
141			name,
142			unique,
143			fields: fields
144				.into_iter()
145				.map(|v| (v.0, v.1.or(default_opclass.clone())))
146				.collect(),
147			using,
148			default_opclass,
149			with,
150		}
151	}
152	pub fn propagate_to_table(mut self, column: ColumnIdent) -> Self {
153		self.fields
154			.insert(0, (column, self.default_opclass.clone()));
155		self
156	}
157	pub fn fields(&self) -> &[(ColumnIdent, Option<OpClass>)] {
158		&self.fields
159	}
160	pub fn field_idents(&self) -> impl IntoIterator<Item = ColumnIdent> + '_ {
161		self.fields().iter().map(|i| i.0)
162	}
163	pub fn clone_for_propagate(&self) -> Self {
164		Self {
165			uid: next_uid(),
166			name: self.name.clone(),
167			unique: self.unique,
168			fields: self.fields.clone(),
169			using: self.using.clone(),
170			default_opclass: self.default_opclass.clone(),
171			with: self.with.clone(),
172		}
173	}
174}
175impl TableIndex<'_> {
176	pub fn db_columns<'i>(&'i self, rn: &'i RenameMap) -> impl Iterator<Item = DbColumn> + 'i {
177		self.fields.iter().map(|f| self.table.db_name(&f.0, rn))
178	}
179	pub fn db_columns_opclass<'i>(
180		&'i self,
181		rn: &'i RenameMap,
182	) -> impl Iterator<Item = (DbColumn, Option<OpClass>)> + 'i {
183		self.fields
184			.iter()
185			.map(|f| (self.table.db_name(&f.0, rn), f.1.clone()))
186	}
187	pub fn db_types<'i>(&'i self, rn: &'i RenameMap, report: &'i mut Report) -> impl Iterator<Item = DbNativeType> + 'i {
188		self.fields
189			.iter()
190			.map(|f| self.table.schema_column(f.0).db_type(rn, report))
191	}
192}