use toasty_core::schema::Name;
use toasty_core::schema::app::IndexId as AppIndexId;
use toasty_core::schema::app::{
Field, FieldName, FieldPrimitive, FieldTy, ModelId, ModelRoot, PrimaryKey as AppPrimaryKey,
};
use toasty_core::schema::db::Type as DbType;
use toasty_core::schema::db::{
Column, ColumnId, IndexId as DbIndexId, PrimaryKey as DbPrimaryKey, Schema, Table, TableId,
};
use toasty_core::stmt::{Expr, ExprColumn, ExprContext, ExprReference, ExprTarget, Type};
fn db_schema(col_types: &[(Type, &str)]) -> Schema {
let table_id = TableId(0);
let columns = col_types
.iter()
.enumerate()
.map(|(i, (ty, name))| Column {
id: ColumnId {
table: table_id,
index: i,
},
name: name.to_string(),
ty: ty.clone(),
storage_ty: DbType::Text,
nullable: false,
primary_key: i == 0,
auto_increment: false,
versionable: false,
})
.collect();
Schema {
tables: vec![Table {
id: table_id,
name: "t".to_string(),
columns,
primary_key: DbPrimaryKey {
columns: vec![ColumnId {
table: table_id,
index: 0,
}],
index: DbIndexId {
table: table_id,
index: 0,
},
},
indices: vec![],
}],
}
}
fn table_cx(schema: &Schema) -> ExprContext<'_, Schema> {
ExprContext::new_with_target(schema, &schema.tables[0])
}
fn model_root(id: usize, field_types: &[(Type, &str)]) -> ModelRoot {
let model_id = ModelId(id);
let fields = field_types
.iter()
.enumerate()
.map(|(i, (ty, name))| Field {
id: model_id.field(i),
name: FieldName {
app: Some(name.to_string()),
storage: None,
},
ty: FieldTy::Primitive(FieldPrimitive {
ty: ty.clone(),
storage_ty: None,
serialize: None,
}),
nullable: false,
primary_key: i == 0,
auto: None,
versionable: false,
constraints: vec![],
variant: None,
})
.collect();
ModelRoot {
id: model_id,
name: Name::new("T"),
fields,
primary_key: AppPrimaryKey {
fields: vec![model_id.field(0)],
index: AppIndexId {
model: model_id,
index: 0,
},
},
table_name: None,
indices: vec![],
version_field: None,
}
}
fn model_cx(model: &ModelRoot) -> ExprContext<'_, ()> {
ExprContext::new_with_target(&(), model)
}
fn col_ref(nesting: usize, column: usize) -> Expr {
Expr::Reference(ExprReference::Column(ExprColumn {
nesting,
table: 0,
column,
}))
}
fn field_ref(nesting: usize, index: usize) -> Expr {
Expr::Reference(ExprReference::Field { nesting, index })
}
fn model_ref(nesting: usize) -> Expr {
Expr::Reference(ExprReference::Model { nesting })
}
#[test]
fn column_nesting0_bool() {
let s = db_schema(&[(Type::Bool, "flag")]);
assert_eq!(table_cx(&s).infer_expr_ty(&col_ref(0, 0), &[]), Type::Bool);
}
#[test]
fn column_nesting0_i64() {
let s = db_schema(&[(Type::I64, "id")]);
assert_eq!(table_cx(&s).infer_expr_ty(&col_ref(0, 0), &[]), Type::I64);
}
#[test]
fn column_nesting0_u64() {
let s = db_schema(&[(Type::U64, "count")]);
assert_eq!(table_cx(&s).infer_expr_ty(&col_ref(0, 0), &[]), Type::U64);
}
#[test]
fn column_nesting0_string() {
let s = db_schema(&[(Type::String, "name")]);
assert_eq!(
table_cx(&s).infer_expr_ty(&col_ref(0, 0), &[]),
Type::String
);
}
#[test]
fn column_nesting0_bytes() {
let s = db_schema(&[(Type::Bytes, "data")]);
assert_eq!(table_cx(&s).infer_expr_ty(&col_ref(0, 0), &[]), Type::Bytes);
}
#[test]
fn column_nesting0_uuid() {
let s = db_schema(&[(Type::Uuid, "id")]);
assert_eq!(table_cx(&s).infer_expr_ty(&col_ref(0, 0), &[]), Type::Uuid);
}
#[test]
fn column_nesting0_selected_by_index() {
let s = db_schema(&[
(Type::I64, "id"),
(Type::String, "name"),
(Type::Bool, "active"),
]);
let cx = table_cx(&s);
assert_eq!(cx.infer_expr_ty(&col_ref(0, 0), &[]), Type::I64);
assert_eq!(cx.infer_expr_ty(&col_ref(0, 1), &[]), Type::String);
assert_eq!(cx.infer_expr_ty(&col_ref(0, 2), &[]), Type::Bool);
}
#[test]
fn column_nesting1_resolves_from_parent() {
let s = db_schema(&[(Type::I64, "id"), (Type::String, "name")]);
let parent = table_cx(&s);
let child = parent.scope(ExprTarget::Free);
assert_eq!(child.infer_expr_ty(&col_ref(1, 0), &[]), Type::I64);
assert_eq!(child.infer_expr_ty(&col_ref(1, 1), &[]), Type::String);
}
#[test]
fn column_nesting2_resolves_from_grandparent() {
let s = db_schema(&[(Type::Bool, "flag")]);
let grandparent = table_cx(&s);
let parent = grandparent.scope(ExprTarget::Free);
let child = parent.scope(ExprTarget::Free);
assert_eq!(child.infer_expr_ty(&col_ref(2, 0), &[]), Type::Bool);
}
#[test]
fn field_nesting0_first_field() {
let m = model_root(0, &[(Type::I64, "id")]);
assert_eq!(model_cx(&m).infer_expr_ty(&field_ref(0, 0), &[]), Type::I64);
}
#[test]
fn field_nesting0_selected_by_index() {
let m = model_root(
0,
&[
(Type::I64, "id"),
(Type::String, "name"),
(Type::Bool, "active"),
],
);
let cx = model_cx(&m);
assert_eq!(cx.infer_expr_ty(&field_ref(0, 0), &[]), Type::I64);
assert_eq!(cx.infer_expr_ty(&field_ref(0, 1), &[]), Type::String);
assert_eq!(cx.infer_expr_ty(&field_ref(0, 2), &[]), Type::Bool);
}
#[test]
fn field_nesting0_uuid() {
let m = model_root(0, &[(Type::Uuid, "id"), (Type::String, "email")]);
let cx = model_cx(&m);
assert_eq!(cx.infer_expr_ty(&field_ref(0, 0), &[]), Type::Uuid);
assert_eq!(cx.infer_expr_ty(&field_ref(0, 1), &[]), Type::String);
}
#[test]
fn field_nesting1_resolves_from_parent() {
let m = model_root(0, &[(Type::I64, "id"), (Type::String, "name")]);
let parent = model_cx(&m);
let child = parent.scope(ExprTarget::Free);
assert_eq!(child.infer_expr_ty(&field_ref(1, 0), &[]), Type::I64);
assert_eq!(child.infer_expr_ty(&field_ref(1, 1), &[]), Type::String);
}
#[test]
fn model_ref_nesting0() {
let m = model_root(0, &[(Type::I64, "id")]);
assert_eq!(
model_cx(&m).infer_expr_ty(&model_ref(0), &[]),
Type::Model(ModelId(0))
);
}
#[test]
fn model_ref_nesting0_distinct_ids() {
let m0 = model_root(0, &[(Type::I64, "id")]);
let m1 = model_root(1, &[(Type::Uuid, "id")]);
assert_eq!(
model_cx(&m0).infer_expr_ty(&model_ref(0), &[]),
Type::Model(ModelId(0))
);
assert_eq!(
model_cx(&m1).infer_expr_ty(&model_ref(0), &[]),
Type::Model(ModelId(1))
);
}
#[test]
fn model_ref_nesting1_resolves_from_parent() {
let m = model_root(42, &[(Type::I64, "id")]);
let parent = model_cx(&m);
let child = parent.scope(ExprTarget::Free);
assert_eq!(
child.infer_expr_ty(&model_ref(1), &[]),
Type::Model(ModelId(42))
);
}