use toasty::Db;
use topcoat::context::CxTestBuilder;
use super::*;
use crate::{Tenancy, TenantId, lens, test_support::User};
struct UserResource;
impl Resource for UserResource {
type Model = User;
type Form = crate::NoForm<Self::Model>;
fn declare() -> ResourceDef<Self> {
ResourceDef::new().table(crate::table::Table::new(crate::table::TextColumn::new(
lens!(User.name),
)))
}
fn query(_cx: &Cx) -> toasty::stmt::Query<List<User>> {
toasty::stmt::Query::<List<User>>::all().filter(User::fields().name().eq("Ada"))
}
}
struct BareResource;
impl Resource for BareResource {
type Model = User;
type Form = crate::NoForm<Self::Model>;
fn declare() -> ResourceDef<Self> {
ResourceDef::new().table(crate::table::Table::new(crate::table::TextColumn::new(
lens!(User.name),
)))
}
}
#[tokio::test]
async fn query_seam_is_cloneable_via_db_helper() {
let mut db = Db::builder()
.models(toasty::models!(User))
.connect("sqlite::memory:")
.await
.unwrap();
db.push_schema().await.unwrap();
toasty::create!(User { name: "Ada" })
.exec(&mut db)
.await
.unwrap();
toasty::create!(User { name: "Bob" })
.exec(&mut db)
.await
.unwrap();
let cx = CxTestBuilder::new().app_context(db).build();
let mut db = crate::db::db(&cx);
let rows = UserResource::query(&cx).exec(&mut db).await.unwrap();
assert_eq!(rows.len(), 1);
assert_eq!(rows[0].name, "Ada");
let rows_all = BareResource::query(&cx).exec(&mut db).await.unwrap();
assert_eq!(rows_all.len(), 2);
}
#[derive(Debug, Clone, toasty::Model)]
struct Owned {
#[key]
#[auto]
id: uuid::Uuid,
tenant_id: TenantId,
name: String,
}
struct OwnedResource;
impl Resource for OwnedResource {
type Model = Owned;
type Form = crate::NoForm<Self::Model>;
fn declare() -> ResourceDef<Self> {
ResourceDef::new()
.tenancy(Tenancy::column(Owned::fields().tenant_id()))
.table(crate::table::Table::new(crate::table::TextColumn::new(
lens!(Owned.name),
)))
}
fn query(_cx: &Cx) -> toasty::stmt::Query<List<Owned>> {
toasty::stmt::Query::<List<Owned>>::all().filter(Owned::fields().name().ne("Hidden"))
}
}
#[tokio::test]
async fn tenancy_is_anded_onto_the_base_query() {
let mut db = Db::builder()
.models(toasty::models!(Owned))
.connect("sqlite::memory:")
.await
.unwrap();
db.push_schema().await.unwrap();
let mine = uuid::Uuid::new_v4();
let theirs = uuid::Uuid::new_v4();
for (tenant_id, name) in [
(TenantId::from(mine), "Mine"),
(TenantId::from(mine), "Hidden"),
(TenantId::from(theirs), "Theirs"),
] {
toasty::create!(Owned { tenant_id, name })
.exec(&mut db)
.await
.unwrap();
}
let tenantless = crate::test_support::panel_cx::<OwnedResource>(&db);
let cx = tenantless.with(crate::Tenant(mine));
let mut db = crate::db::db(&cx);
let rows = scoped_query::<OwnedResource>(&cx)
.expect("the request has a tenant")
.exec(&mut db)
.await
.unwrap();
assert_eq!(rows.len(), 1);
assert_eq!(rows[0].name, "Mine");
assert!(scoped_query::<OwnedResource>(&tenantless).is_err());
}
#[derive(Debug, Clone, toasty::Model)]
struct Assignable {
#[key]
#[auto]
id: uuid::Uuid,
tenant_id: Option<TenantId>,
name: String,
}
struct AssignableResource;
impl Resource for AssignableResource {
type Model = Assignable;
type Form = OptionTenantForm;
fn declare() -> ResourceDef<Self> {
ResourceDef::new()
.tenancy(Tenancy::column(Assignable::fields().tenant_id()))
.table(crate::table::Table::new(crate::table::TextColumn::new(
lens!(Assignable.name),
)))
}
}
#[derive(crate::RecordForm)]
#[form(model = Assignable)]
struct OptionTenantForm {
name: String,
}
#[tokio::test]
async fn a_nullable_tenant_column_is_stamped_and_scoped() {
let mut db = Db::builder()
.models(toasty::models!(Assignable))
.connect("sqlite::memory:")
.await
.unwrap();
db.push_schema().await.unwrap();
let mine = uuid::Uuid::new_v4();
let theirs = uuid::Uuid::new_v4();
for (tenant_id, name) in [(Some(TenantId::from(theirs)), "Theirs"), (None, "Nobody")] {
toasty::create!(Assignable { tenant_id, name })
.exec(&mut db)
.await
.unwrap();
}
let cx = crate::test_support::panel_cx::<AssignableResource>(&db).with(crate::Tenant(mine));
let mut db = crate::db::db(&cx);
let created = write_create::<AssignableResource>(
&cx,
OptionTenantForm {
name: "Mine".to_string(),
},
&mut db,
)
.await
.expect("the create runs");
assert_eq!(created.tenant_id, Some(TenantId::from(mine)));
let rows = scoped_query::<AssignableResource>(&cx)
.expect("the request has a tenant")
.exec(&mut db)
.await
.unwrap();
assert_eq!(rows.len(), 1, "only the request tenant's row is served");
assert_eq!(rows[0].name, "Mine");
}