Skip to content

Commit

Permalink
split app & db schemas (#59)
Browse files Browse the repository at this point in the history
  • Loading branch information
carllerche authored Jan 24, 2025
1 parent 48b5860 commit 06e52d4
Show file tree
Hide file tree
Showing 21 changed files with 306 additions and 303 deletions.
3 changes: 0 additions & 3 deletions src/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ pub use driver::Driver;
#[macro_use]
mod error;

mod lowering;
pub use lowering::{IndexLowering, Lowering};

pub mod schema;
pub use schema::Schema;

Expand Down
33 changes: 0 additions & 33 deletions src/core/src/lowering.rs

This file was deleted.

22 changes: 20 additions & 2 deletions src/core/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ pub(crate) use builder::Builder;

pub mod db;

pub mod mapping;
use mapping::Mapping;

mod name;
pub use name::Name;

Expand All @@ -17,13 +20,16 @@ use db::{ColumnId, IndexId, Table, TableId};

use std::sync::Arc;

#[derive(Debug, Default)]
#[derive(Debug)]
pub struct Schema {
/// Application-level schema
pub app: app::Schema,

/// Database-level schema
pub db: Arc<db::Schema>,

/// Maps the app-level schema to the db-level schema
pub mapping: Mapping,
}

pub fn from_file(path: impl AsRef<std::path::Path>) -> Result<Schema> {
Expand Down Expand Up @@ -60,12 +66,24 @@ impl Schema {
.expect("invalid field ID")
}

pub fn mapping_for(&self, id: impl Into<ModelId>) -> &mapping::Model {
self.mapping.model(id)
}

pub fn query(&self, id: impl Into<QueryId>) -> &Query {
let id = id.into();
&self.app.queries[id.0]
}

pub fn table_for(&self, id: impl Into<ModelId>) -> &Table {
self.db.table(self.table_id_for(id))
}

pub fn table_id_for(&self, id: impl Into<ModelId>) -> TableId {
self.mapping.model(id).table
}

pub(crate) fn from_ast(ast: &ast::Schema) -> Result<Schema> {
schema::Builder::default().from_ast(ast)
schema::Builder::from_ast(ast)
}
}
5 changes: 1 addition & 4 deletions src/core/src/schema/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@ pub use scope::ScopedQuery;

use super::{
db::{IndexOp, IndexScope},
Lowering, Name,
Name,
};
use crate::{ast, stmt};

// TODO: remove
use crate::schema::{lowering::IndexLowering, ColumnId, IndexId, TableId};
8 changes: 0 additions & 8 deletions src/core/src/schema/app/field/primitive.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
use super::*;

use crate::schema::ColumnId;

#[derive(Debug, PartialEq)]
pub struct FieldPrimitive {
/// Which table column the field is mapped to
pub column: ColumnId,

/// Which index in the lowering map lowers this field.
pub lowering: usize,

/// The field's primitive type
pub ty: stmt::Type,
}
19 changes: 3 additions & 16 deletions src/core/src/schema/app/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ pub struct Model {
/// Name of the model
pub name: Name,

/// Describes how to lower the model to a table
pub lowering: Lowering,

/// Fields contained by the model
pub fields: Vec<Field>,

Expand Down Expand Up @@ -83,22 +80,12 @@ impl Model {
.map(|pk_field| &self.fields[pk_field.index])
}

pub fn primary_key_primitives<'a>(&'a self) -> impl Iterator<Item = &'a FieldPrimitive> + 'a {
pub(crate) fn primary_key_primitives<'a>(
&'a self,
) -> impl Iterator<Item = &'a FieldPrimitive> + 'a {
self.primary_key_fields()
.map(|field| field.ty.expect_primitive())
}

pub(crate) fn primary_key_primitives_mut<'a>(
&'a mut self,
) -> impl Iterator<Item = &'a mut FieldPrimitive> + 'a {
// Some stupidly annoying code to avoid unsafe...
let mut fields = self.fields.iter_mut().map(Some).collect::<Vec<_>>();
self.primary_key
.fields
.iter()
.map(move |pk_field| fields[pk_field.index].take().unwrap())
.map(|field| field.ty.expect_primitive_mut())
}
}

impl ModelId {
Expand Down
19 changes: 1 addition & 18 deletions src/core/src/schema/app/model/from_ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,6 @@ impl Model {
model: Model {
id,
name: Name::new(&node.ident.to_string()),
lowering: Lowering {
table: TableId::placeholder(),
columns: vec![],
model_pk_to_table: stmt::Expr::default(),
table_to_model: stmt::ExprRecord::default(),
model_to_table: stmt::ExprRecord::default(),
},
fields: vec![],
primary_key: PrimaryKey {
fields: vec![],
Expand All @@ -40,9 +33,6 @@ impl Model {
fields: vec![],
unique: true,
primary_key: true,
lowering: IndexLowering {
index: IndexId::placeholder(),
},
}],
table_name: None,
},
Expand Down Expand Up @@ -133,9 +123,6 @@ impl<'a> Builder<'a> {
}],
unique: attr.is_unique(),
primary_key: false,
lowering: IndexLowering {
index: IndexId::placeholder(),
},
});
}

Expand Down Expand Up @@ -260,11 +247,7 @@ impl<'a> Builder<'a> {
self.model.fields.push(Field {
id,
name: name.clone(),
ty: FieldTy::Primitive(FieldPrimitive {
column: ColumnId::placeholder(),
lowering: usize::MAX,
ty,
}),
ty: FieldTy::Primitive(FieldPrimitive { ty }),
primary_key: false,
nullable,
auto: None,
Expand Down
2 changes: 0 additions & 2 deletions src/core/src/schema/app/model/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ pub struct ModelIndex {

/// When true, the index is the primary key
pub primary_key: bool,

pub lowering: IndexLowering,
}

#[derive(Debug, PartialEq)]
Expand Down
104 changes: 54 additions & 50 deletions src/core/src/schema/builder.rs
Original file line number Diff line number Diff line change
@@ -1,74 +1,78 @@
mod table;

use super::*;

use std::collections::HashMap;

/// Used to resolve types during parsing
#[derive(Default)]
pub(crate) struct Builder {
/// Maps table names to identifiers. The identifiers are reserved before the
/// table objects are actually created.
table_lookup: HashMap<String, TableId>,

// ----- OLD -----
/// Tables as they are built
pub(crate) tables: Vec<Table>,

/// App-level to db-level schema mapping
pub(crate) mapping: Mapping,
}

impl Builder {
pub(crate) fn from_ast(mut self, ast: &ast::Schema) -> crate::Result<Schema> {
let mut ctx = db::Context::new();
pub(crate) fn from_ast(ast: &ast::Schema) -> crate::Result<Schema> {
let app = app::Schema::from_ast(ast)?;
let mut builder = Builder {
table_lookup: HashMap::new(),

let mut app_schema = app::Schema::from_ast(ast)?;
tables: vec![],
mapping: Mapping { models: vec![] },
};

// Find all models that specified a table name, ensure a table is
// created for that model, and link the model with the table.
for model in &mut app_schema.models {
let Some(table_name) = &model.table_name else {
continue;
};

let contains_table = self
.tables
.iter()
.find(|table| table.name == *table_name)
.is_some();
for model in &app.models {
let table = if let Some(table_name) = &model.table_name {
if !builder.table_lookup.contains_key(table_name) {
let id = builder.register_table(&table_name);
builder.tables.push(Table::new(id, table_name.clone()));
}

if !contains_table {
let id = ctx.register_table(&table_name);
self.tables.push(Table::new(id, table_name.clone()));
}

let table = self
.tables
.iter()
.find(|table| table.name == *table_name)
.unwrap();

model.lowering.table = table.id;
}
builder.table_lookup.get(table_name).unwrap().clone()
} else {
builder.build_table_stub_for_model(model)
};

// Find all defined tables and generate their schema based on assigned
// models
for table in &mut self.tables {
let mut models = app_schema
.models
.iter_mut()
.filter(|model| model.lowering.table == table.id)
.collect::<Vec<_>>();
table.lower_models(&mut models);
// Create a mapping stub for the model
builder.mapping.models.push(mapping::Model {
id: model.id,
table,
columns: vec![],
// Create a mapping stub for each primitive field
fields: model
.fields
.iter()
.map(|field| match &field.ty {
app::FieldTy::Primitive(_) => Some(mapping::Field {
column: ColumnId::placeholder(),
lowering: 0,
}),
_ => None,
})
.collect(),
model_to_table: stmt::ExprRecord::default(),
model_pk_to_table: stmt::Expr::default(),
table_to_model: stmt::ExprRecord::default(),
});
}

// Now, we can initialize tables for each model. Mutability is needed so
// that the model can be updated to reference the newly created tables
// and columns.
for model in &mut app_schema.models {
if model.lowering.table != TableId::placeholder() {
continue;
}

let table = Table::from_model(&mut ctx, model)?;
assert_eq!(self.tables.len(), table.id.0);
self.tables.push(table);
}
builder.build_tables_from_models(&app);

let schema = Schema {
app: app_schema,
app,
db: Arc::new(db::Schema {
tables: self.tables,
tables: builder.tables,
}),
mapping: builder.mapping,
};

// Verify the schema structure
Expand Down
Loading

0 comments on commit 06e52d4

Please sign in to comment.