Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split app & db schema #59

Merged
merged 1 commit into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading