1use crate::{SchemaError, ValueShapeValidator};
2use sim_kernel::{Datum, Symbol};
3use sim_relation_core::{
4 ColumnName, ConstraintName, DomainCatalog, DomainId, IndexName, RelationId, SchemaName,
5 TableName, ToRelationDatum, ViewName,
6};
7
8#[derive(Clone, Debug, PartialEq, Eq)]
10pub struct DefaultValue(pub Datum);
11#[derive(Clone, Debug, PartialEq, Eq)]
13pub struct GeneratedValue {
14 pub(crate) expression: Datum,
15 pub(crate) depends_on: Vec<ColumnName>,
16}
17impl GeneratedValue {
18 pub fn new(expression: Datum, depends_on: impl IntoIterator<Item = ColumnName>) -> Self {
20 Self {
21 expression,
22 depends_on: depends_on.into_iter().collect(),
23 }
24 }
25}
26#[derive(Clone, Debug, PartialEq, Eq)]
28pub struct Column {
29 pub(crate) name: ColumnName,
30 pub(crate) domain: DomainId,
31 pub(crate) nullable: bool,
32 pub(crate) default: Option<DefaultValue>,
33 pub(crate) generated: Option<GeneratedValue>,
34}
35impl Column {
36 pub fn name(&self) -> &ColumnName {
38 &self.name
39 }
40 pub fn domain(&self) -> &DomainId {
42 &self.domain
43 }
44 pub const fn nullable(&self) -> bool {
46 self.nullable
47 }
48 pub const fn has_default(&self) -> bool {
50 self.default.is_some()
51 }
52 pub const fn is_generated(&self) -> bool {
54 self.generated.is_some()
55 }
56}
57#[derive(Clone, Debug, PartialEq, Eq)]
59pub struct PrimaryKey {
60 pub name: ConstraintName,
62 pub columns: Vec<ColumnName>,
64}
65#[derive(Clone, Debug, PartialEq, Eq)]
67pub struct UniqueConstraint {
68 pub name: ConstraintName,
70 pub columns: Vec<ColumnName>,
72}
73#[derive(Clone, Debug, PartialEq, Eq)]
75pub struct CheckConstraint {
76 pub name: ConstraintName,
78 pub expression: Datum,
80 pub columns: Vec<ColumnName>,
82}
83#[derive(Clone, Debug, PartialEq, Eq)]
85pub struct ForeignKey {
86 pub name: ConstraintName,
88 pub columns: Vec<ColumnName>,
90 pub target_table: TableName,
92 pub target_columns: Vec<ColumnName>,
94}
95#[derive(Clone, Debug, PartialEq, Eq)]
97pub enum Constraint {
98 Primary(PrimaryKey),
100 Unique(UniqueConstraint),
102 Check(CheckConstraint),
104 Foreign(ForeignKey),
106}
107impl Constraint {
108 pub(crate) fn name(&self) -> &ConstraintName {
109 match self {
110 Self::Primary(v) => &v.name,
111 Self::Unique(v) => &v.name,
112 Self::Check(v) => &v.name,
113 Self::Foreign(v) => &v.name,
114 }
115 }
116}
117#[derive(Clone, Debug, PartialEq, Eq)]
119pub struct Index {
120 pub name: IndexName,
122 pub columns: Vec<ColumnName>,
124 pub unique: bool,
126}
127#[derive(Clone, Debug, PartialEq, Eq)]
129pub struct Table {
130 pub(crate) name: TableName,
131 pub(crate) columns: Vec<Column>,
132 pub(crate) constraints: Vec<Constraint>,
133 pub(crate) indexes: Vec<Index>,
134}
135impl Table {
136 pub fn name(&self) -> &TableName {
138 &self.name
139 }
140 pub fn columns(&self) -> &[Column] {
142 &self.columns
143 }
144 pub fn constraints(&self) -> &[Constraint] {
146 &self.constraints
147 }
148 pub fn indexes(&self) -> &[Index] {
150 &self.indexes
151 }
152}
153#[derive(Clone, Debug, PartialEq, Eq)]
155pub struct View {
156 pub name: ViewName,
158 pub query: Datum,
160 pub table_dependencies: Vec<TableName>,
162 pub view_dependencies: Vec<ViewName>,
164}
165#[derive(Clone, Debug, PartialEq, Eq)]
167pub struct Schema {
168 pub(crate) name: SchemaName,
169 pub(crate) tables: Vec<Table>,
170 pub(crate) views: Vec<View>,
171}
172impl Schema {
173 pub fn new(
175 name: SchemaName,
176 tables: impl IntoIterator<Item = Table>,
177 views: impl IntoIterator<Item = View>,
178 domains: &DomainCatalog,
179 validator: &impl ValueShapeValidator,
180 ) -> Result<Self, SchemaError> {
181 crate::validation::validate(
182 name,
183 tables.into_iter().collect(),
184 views.into_iter().collect(),
185 domains,
186 validator,
187 )
188 }
189 pub fn name(&self) -> &SchemaName {
191 &self.name
192 }
193 pub fn tables(&self) -> &[Table] {
195 &self.tables
196 }
197 pub fn views(&self) -> &[View] {
199 &self.views
200 }
201 pub fn id(&self) -> Result<RelationId, sim_kernel::Error> {
203 RelationId::of(self)
204 }
205}
206
207fn sym(name: &str, value: Symbol) -> (Symbol, Datum) {
208 (Symbol::new(name), Datum::Symbol(value))
209}
210fn node(tag: &str, fields: Vec<(Symbol, Datum)>) -> Datum {
211 Datum::Node {
212 tag: Symbol::qualified("relation-schema", tag),
213 fields,
214 }
215}
216fn names<T>(values: &[T], f: impl Fn(&T) -> Symbol) -> Datum {
217 Datum::Vector(values.iter().map(|v| Datum::Symbol(f(v))).collect())
218}
219impl ToRelationDatum for Column {
220 fn to_datum(&self) -> Datum {
221 node(
222 "column",
223 vec![
224 sym("name", self.name.symbol().clone()),
225 sym("domain", self.domain.symbol().clone()),
226 (Symbol::new("nullable"), Datum::Bool(self.nullable)),
227 (
228 Symbol::new("default"),
229 self.default.as_ref().map_or(Datum::Nil, |v| v.0.clone()),
230 ),
231 (
232 Symbol::new("generated"),
233 self.generated.as_ref().map_or(Datum::Nil, |v| {
234 node(
235 "generated",
236 vec![
237 (Symbol::new("expression"), v.expression.clone()),
238 (
239 Symbol::new("depends-on"),
240 names(&v.depends_on, |n| n.symbol().clone()),
241 ),
242 ],
243 )
244 }),
245 ),
246 ],
247 )
248 }
249}
250impl ToRelationDatum for Constraint {
251 fn to_datum(&self) -> Datum {
252 match self {
253 Self::Primary(v) => node(
254 "primary",
255 vec![
256 sym("name", v.name.symbol().clone()),
257 (
258 Symbol::new("columns"),
259 names(&v.columns, |n| n.symbol().clone()),
260 ),
261 ],
262 ),
263 Self::Unique(v) => node(
264 "unique",
265 vec![
266 sym("name", v.name.symbol().clone()),
267 (
268 Symbol::new("columns"),
269 names(&v.columns, |n| n.symbol().clone()),
270 ),
271 ],
272 ),
273 Self::Check(v) => node(
274 "check",
275 vec![
276 sym("name", v.name.symbol().clone()),
277 (Symbol::new("expression"), v.expression.clone()),
278 (
279 Symbol::new("columns"),
280 names(&v.columns, |n| n.symbol().clone()),
281 ),
282 ],
283 ),
284 Self::Foreign(v) => node(
285 "foreign",
286 vec![
287 sym("name", v.name.symbol().clone()),
288 (
289 Symbol::new("columns"),
290 names(&v.columns, |n| n.symbol().clone()),
291 ),
292 sym("target-table", v.target_table.symbol().clone()),
293 (
294 Symbol::new("target-columns"),
295 names(&v.target_columns, |n| n.symbol().clone()),
296 ),
297 ],
298 ),
299 }
300 }
301}
302impl ToRelationDatum for Index {
303 fn to_datum(&self) -> Datum {
304 node(
305 "index",
306 vec![
307 sym("name", self.name.symbol().clone()),
308 (
309 Symbol::new("columns"),
310 names(&self.columns, |n| n.symbol().clone()),
311 ),
312 (Symbol::new("unique"), Datum::Bool(self.unique)),
313 ],
314 )
315 }
316}
317impl ToRelationDatum for Table {
318 fn to_datum(&self) -> Datum {
319 node(
320 "table",
321 vec![
322 sym("name", self.name.symbol().clone()),
323 (
324 Symbol::new("columns"),
325 Datum::Vector(self.columns.iter().map(ToRelationDatum::to_datum).collect()),
326 ),
327 (
328 Symbol::new("constraints"),
329 Datum::Vector(
330 self.constraints
331 .iter()
332 .map(ToRelationDatum::to_datum)
333 .collect(),
334 ),
335 ),
336 (
337 Symbol::new("indexes"),
338 Datum::Vector(self.indexes.iter().map(ToRelationDatum::to_datum).collect()),
339 ),
340 ],
341 )
342 }
343}
344impl ToRelationDatum for View {
345 fn to_datum(&self) -> Datum {
346 node(
347 "view",
348 vec![
349 sym("name", self.name.symbol().clone()),
350 (Symbol::new("query"), self.query.clone()),
351 (
352 Symbol::new("tables"),
353 names(&self.table_dependencies, |n| n.symbol().clone()),
354 ),
355 (
356 Symbol::new("views"),
357 names(&self.view_dependencies, |n| n.symbol().clone()),
358 ),
359 ],
360 )
361 }
362}
363impl ToRelationDatum for Schema {
364 fn to_datum(&self) -> Datum {
365 node(
366 "logical-schema",
367 vec![
368 sym("name", self.name.symbol().clone()),
369 (
370 Symbol::new("tables"),
371 Datum::Vector(self.tables.iter().map(ToRelationDatum::to_datum).collect()),
372 ),
373 (
374 Symbol::new("views"),
375 Datum::Vector(self.views.iter().map(ToRelationDatum::to_datum).collect()),
376 ),
377 ],
378 )
379 }
380}