use crate::prelude::*;
use toasty_core::{
driver::Operation,
stmt::{Expr, ExprSet, Statement},
};
#[driver_test(id(ID))]
pub async fn query_index_eq(test: &mut Test) -> Result<()> {
#[derive(Debug, toasty::Model)]
struct User {
#[key]
#[auto]
id: ID,
#[index]
name: String,
email: String,
}
let mut db = test.setup_db(models!(User)).await;
for &(name, email) in &[
("one", "one@example.com"),
("two", "two@example.com"),
("three", "three@example.com"),
] {
User::create().name(name).email(email).exec(&mut db).await?;
}
let users = User::filter_by_name("one").exec(&mut db).await?;
assert_eq!(1, users.len());
assert_eq!("one", users[0].name);
User::create()
.name("one")
.email("one-two@example.com")
.exec(&mut db)
.await?;
let mut users = User::filter_by_name("one").exec(&mut db).await?;
users.sort_by_key(|u| u.email.clone());
assert_eq!(2, users.len());
assert_eq!("one", users[0].name);
assert_eq!("one-two@example.com", users[0].email);
assert_eq!("one", users[1].name);
assert_eq!("one@example.com", users[1].email);
Ok(())
}
#[driver_test(id(ID))]
pub async fn query_partition_key_string_eq(test: &mut Test) -> Result<()> {
#[derive(Debug, toasty::Model)]
#[key(partition = league, local = name)]
struct Team {
league: String,
name: String,
founded: i64,
}
let mut db = test.setup_db(models!(Team)).await;
for (league, name, founded) in [
("MLS", "Portland Timbers", 2009),
("MLS", "Seattle Sounders FC", 2007),
("MLS", "Vancouver Whitecaps FC", 2009),
("MLS", "Los Angeles Football Club", 2014),
("MLS", "San Jose Earthquakes", 1994),
("MLS", "LA Galaxy", 1994),
("EPL", "Arsenal", 1886),
("EPL", "Chelsea", 1905),
("EPL", "Manchester United", 1878),
("EPL", "Tottenham", 1882),
("La Liga", "FC Barcelona", 1899),
("La Liga", "Girona FC", 1930),
("La Liga", "Real Madrid", 1902),
("La Liga", "Atlético Madrid", 1903),
]
.into_iter()
{
Team::create()
.league(league)
.name(name)
.founded(founded)
.exec(&mut db)
.await?;
}
let teams = Team::filter(Team::fields().league().eq("EPL"))
.exec(&mut db)
.await?;
let mut names = teams.iter().map(|team| &team.name).collect::<Vec<_>>();
names.sort();
assert_eq!(
names,
["Arsenal", "Chelsea", "Manchester United", "Tottenham"]
);
let teams = Team::filter(
Team::fields()
.league()
.eq("MLS")
.and(Team::fields().name().eq("Portland Timbers")),
)
.exec(&mut db)
.await?;
let mut names = teams.iter().map(|team| &team.name).collect::<Vec<_>>();
names.sort();
assert_eq!(names, ["Portland Timbers"]);
let teams = Team::filter(
Team::fields()
.league()
.eq("MLS")
.and(Team::fields().founded().eq(2009)),
)
.exec(&mut db)
.await?;
let mut names = teams.iter().map(|team| &team.name).collect::<Vec<_>>();
names.sort();
assert_eq!(names, ["Portland Timbers", "Vancouver Whitecaps FC"]);
let teams = Team::filter(
Team::fields()
.league()
.eq("MLS")
.and(Team::fields().founded().eq(2009))
.and(Team::fields().name().eq("Portland Timbers")),
)
.exec(&mut db)
.await?;
assert_eq!(1, teams.len());
assert!(teams.iter().all(|team| team.founded == 2009));
let mut names = teams.iter().map(|team| &team.name).collect::<Vec<_>>();
names.sort();
assert_eq!(names, ["Portland Timbers"]);
let teams = Team::filter(
Team::fields()
.league()
.eq("MLS")
.and(Team::fields().founded().eq(2009))
.and(Team::fields().name().eq("LA Galaxy")),
)
.exec(&mut db)
.await?;
assert!(teams.is_empty());
Ok(())
}
#[driver_test(id(ID))]
pub async fn query_local_key_cmp(test: &mut Test) -> Result<()> {
#[derive(Debug, toasty::Model)]
#[key(partition = kind, local = timestamp)]
struct Event {
kind: String,
timestamp: i64,
}
let mut db = test.setup_db(models!(Event)).await;
for (kind, ts) in [
("info", 0),
("warn", 1),
("info", 2),
("warn", 3),
("info", 4),
("warn", 5),
("info", 6),
("warn", 7),
("info", 8),
("warn", 9),
("info", 10),
("warn", 11),
("info", 12),
("warn", 13),
("info", 14),
("warn", 15),
("info", 16),
("warn", 17),
("info", 18),
("warn", 19),
] {
Event::create()
.kind(kind)
.timestamp(ts)
.exec(&mut db)
.await?;
}
let events: Vec<_> = Event::filter_by_kind("info")
.filter(Event::fields().timestamp().ne(10))
.exec(&mut db)
.await?;
assert_eq_unordered!(
events.iter().map(|event| event.timestamp),
[&0, &2, &4, &6, &8, &12, &14, &16, &18,]
);
let events: Vec<_> = Event::filter_by_kind("info")
.filter(Event::fields().timestamp().gt(10))
.exec(&mut db)
.await?;
assert_eq_unordered!(
events.iter().map(|event| event.timestamp),
[&12, &14, &16, &18,]
);
let events: Vec<_> = Event::filter_by_kind("info")
.filter(Event::fields().timestamp().ge(10))
.exec(&mut db)
.await?;
assert_eq_unordered!(
events.iter().map(|event| event.timestamp),
[&10, &12, &14, &16, &18,]
);
let events: Vec<_> = Event::filter_by_kind("info")
.filter(Event::fields().timestamp().lt(10))
.exec(&mut db)
.await?;
assert_eq_unordered!(
events.iter().map(|event| event.timestamp),
[&0, &2, &4, &6, &8]
);
let events: Vec<_> = Event::filter_by_kind("info")
.filter(Event::fields().timestamp().le(10))
.exec(&mut db)
.await?;
assert_eq_unordered!(
events.iter().map(|event| event.timestamp),
[&0, &2, &4, &6, &8, &10]
);
Ok(())
}
#[driver_test(id(ID))]
pub async fn query_or_basic(test: &mut Test) -> Result<()> {
#[derive(Debug, toasty::Model)]
struct User {
#[key]
#[auto]
id: ID,
name: String,
#[allow(dead_code)]
age: i64,
}
let mut db = test.setup_db(models!(User)).await;
let _name_column = db.schema().table_for(User::id()).columns[1].id;
let _age_column = db.schema().table_for(User::id()).columns[2].id;
for (name, age) in [("Alice", 25), ("Bob", 30), ("Charlie", 35), ("Diana", 40)] {
User::create().name(name).age(age).exec(&mut db).await?;
}
test.log().clear();
let result = User::filter(
User::fields()
.name()
.eq("Alice")
.or(User::fields().age().eq(35)),
)
.exec(&mut db)
.await;
if test.capability().sql {
let users = result?;
assert_eq!(2, users.len());
let mut names: Vec<_> = users.iter().map(|u| u.name.as_str()).collect();
names.sort();
assert_eq!(names, ["Alice", "Charlie"]);
let (op, _) = test.log().pop();
assert_struct!(&op, Operation::QuerySql({
stmt: Statement::Query({
body: ExprSet::Select({
filter.expr: Some(Expr::Or({
})),
}),
}),
}));
} else {
assert!(
result.is_err(),
"Expected error for OR query without key condition on non-SQL database"
);
}
Ok(())
}
#[driver_test(id(ID))]
pub async fn query_or_multiple(test: &mut Test) -> Result<()> {
#[derive(Debug, toasty::Model)]
struct User {
#[key]
#[auto]
id: ID,
name: String,
#[allow(dead_code)]
age: i64,
}
let mut db = test.setup_db(models!(User)).await;
for (name, age) in [("Alice", 25), ("Bob", 30), ("Charlie", 35), ("Diana", 40)] {
User::create().name(name).age(age).exec(&mut db).await?;
}
let result = User::filter(
User::fields()
.name()
.eq("Alice")
.or(User::fields().age().eq(35))
.or(User::fields().age().eq(40)),
)
.exec(&mut db)
.await;
if test.capability().sql {
let users = result?;
assert_eq!(3, users.len());
let mut names: Vec<_> = users.iter().map(|u| u.name.as_str()).collect();
names.sort();
assert_eq!(names, ["Alice", "Charlie", "Diana"]);
} else {
assert!(
result.is_err(),
"Expected error for OR query without key condition on non-SQL database"
);
}
Ok(())
}
#[driver_test(id(ID))]
pub async fn query_or_and_combined(test: &mut Test) -> Result<()> {
#[derive(Debug, toasty::Model)]
struct User {
#[key]
#[auto]
id: ID,
name: String,
#[allow(dead_code)]
age: i64,
#[allow(dead_code)]
active: bool,
}
let mut db = test.setup_db(models!(User)).await;
for (name, age, active) in [
("Alice", 25, true),
("Bob", 30, false),
("Charlie", 35, true),
("Diana", 40, false),
("Eve", 25, false),
] {
User::create()
.name(name)
.age(age)
.active(active)
.exec(&mut db)
.await?;
}
let result = User::filter(
User::fields()
.name()
.eq("Alice")
.or(User::fields().age().eq(35))
.and(User::fields().active().eq(true)),
)
.exec(&mut db)
.await;
if test.capability().sql {
let users = result?;
assert_eq!(2, users.len());
let mut names: Vec<_> = users.iter().map(|u| u.name.as_str()).collect();
names.sort();
assert_eq!(names, ["Alice", "Charlie"]);
} else {
assert!(
result.is_err(),
"Expected error for OR query without key condition on non-SQL database"
);
}
Ok(())
}
#[driver_test(id(ID))]
pub async fn query_or_with_index(test: &mut Test) -> Result<()> {
#[derive(Debug, toasty::Model)]
#[key(partition = team, local = name)]
struct Player {
team: String,
name: String,
#[allow(dead_code)]
position: String,
#[allow(dead_code)]
number: i64,
}
let mut db = test.setup_db(models!(Player)).await;
for (team, name, position, number) in [
("Timbers", "Diego Valeri", "Midfielder", 8),
("Timbers", "Darlington Nagbe", "Midfielder", 6),
("Timbers", "Diego Chara", "Midfielder", 21),
("Timbers", "Fanendo Adi", "Forward", 9),
("Timbers", "Adam Kwarasey", "Goalkeeper", 1),
("Sounders", "Clint Dempsey", "Forward", 2),
("Sounders", "Obafemi Martins", "Forward", 9),
("Sounders", "Osvaldo Alonso", "Midfielder", 6),
] {
Player::create()
.team(team)
.name(name)
.position(position)
.number(number)
.exec(&mut db)
.await?;
}
let players = Player::filter(
Player::fields().team().eq("Timbers").and(
Player::fields()
.position()
.eq("Forward")
.or(Player::fields().position().eq("Goalkeeper")),
),
)
.exec(&mut db)
.await?;
assert_eq!(2, players.len());
let mut names: Vec<_> = players.iter().map(|p| p.name.as_str()).collect();
names.sort();
assert_eq!(names, ["Adam Kwarasey", "Fanendo Adi"]);
let players = Player::filter(
Player::fields().team().eq("Timbers").and(
Player::fields()
.number()
.eq(8)
.or(Player::fields().number().eq(21))
.or(Player::fields().number().eq(9)),
),
)
.exec(&mut db)
.await?;
assert_eq!(3, players.len());
let mut names: Vec<_> = players.iter().map(|p| p.name.as_str()).collect();
names.sort();
assert_eq!(names, ["Diego Chara", "Diego Valeri", "Fanendo Adi"]);
Ok(())
}
#[driver_test(id(ID))]
pub async fn query_or_on_partition_key(test: &mut Test) -> Result<()> {
#[derive(Debug, toasty::Model)]
#[key(partition = team, local = name)]
struct Player {
team: String,
name: String,
#[allow(dead_code)]
position: String,
}
let mut db = test.setup_db(models!(Player)).await;
for (team, name, position) in [
("Timbers", "Diego Valeri", "Midfielder"),
("Timbers", "Fanendo Adi", "Forward"),
("Sounders", "Clint Dempsey", "Forward"),
("Sounders", "Osvaldo Alonso", "Midfielder"),
("Galaxy", "Robbie Keane", "Forward"),
] {
Player::create()
.team(team)
.name(name)
.position(position)
.exec(&mut db)
.await?;
}
let players = Player::filter(
Player::fields()
.team()
.eq("Timbers")
.or(Player::fields().team().eq("Sounders")),
)
.exec(&mut db)
.await?;
assert_eq!(4, players.len());
let mut names: Vec<_> = players.iter().map(|p| p.name.as_str()).collect();
names.sort();
assert_eq!(
names,
[
"Clint Dempsey",
"Diego Valeri",
"Fanendo Adi",
"Osvaldo Alonso"
]
);
Ok(())
}
#[driver_test(id(ID))]
pub async fn query_or_on_composite_pk(test: &mut Test) -> Result<()> {
#[derive(Debug, toasty::Model)]
#[key(partition = team, local = name)]
struct Player {
team: String,
name: String,
#[allow(dead_code)]
position: String,
}
let mut db = test.setup_db(models!(Player)).await;
for (team, name, position) in [
("Timbers", "Diego Valeri", "Midfielder"),
("Timbers", "Fanendo Adi", "Forward"),
("Sounders", "Clint Dempsey", "Forward"),
("Sounders", "Osvaldo Alonso", "Midfielder"),
] {
Player::create()
.team(team)
.name(name)
.position(position)
.exec(&mut db)
.await?;
}
let players = Player::filter(
Player::fields()
.team()
.eq("Timbers")
.and(Player::fields().name().eq("Diego Valeri"))
.or(Player::fields()
.team()
.eq("Sounders")
.and(Player::fields().name().eq("Clint Dempsey"))),
)
.exec(&mut db)
.await?;
assert_eq!(2, players.len());
let mut names: Vec<_> = players.iter().map(|p| p.name.as_str()).collect();
names.sort();
assert_eq!(names, ["Clint Dempsey", "Diego Valeri"]);
Ok(())
}
#[driver_test(id(ID))]
pub async fn query_or_with_comparisons(test: &mut Test) -> Result<()> {
#[derive(Debug, toasty::Model)]
#[key(partition = team, local = name)]
struct Player {
team: String,
name: String,
#[allow(dead_code)]
position: String,
#[allow(dead_code)]
number: i64,
}
let mut db = test.setup_db(models!(Player)).await;
for (team, name, position, number) in [
("Timbers", "Diego Valeri", "Midfielder", 8),
("Timbers", "Darlington Nagbe", "Midfielder", 6),
("Timbers", "Diego Chara", "Midfielder", 21),
("Timbers", "Fanendo Adi", "Forward", 9),
("Timbers", "Adam Kwarasey", "Goalkeeper", 1),
("Sounders", "Clint Dempsey", "Forward", 2),
("Sounders", "Obafemi Martins", "Forward", 9),
("Sounders", "Osvaldo Alonso", "Midfielder", 6),
] {
Player::create()
.team(team)
.name(name)
.position(position)
.number(number)
.exec(&mut db)
.await?;
}
let players = Player::filter(
Player::fields().team().eq("Timbers").and(
Player::fields()
.number()
.gt(20)
.or(Player::fields().number().lt(2)),
),
)
.exec(&mut db)
.await?;
assert_eq!(2, players.len());
let mut names: Vec<_> = players.iter().map(|p| p.name.as_str()).collect();
names.sort();
assert_eq!(names, ["Adam Kwarasey", "Diego Chara"]);
Ok(())
}
#[driver_test(id(ID), requires(sql))]
pub async fn query_arbitrary_constraint(test: &mut Test) -> Result<()> {
#[derive(Debug, toasty::Model)]
struct Event {
#[key]
#[auto]
id: ID,
kind: String,
timestamp: i64,
}
let mut db = test.setup_db(models!(Event)).await;
for (kind, ts) in [
("info", 0),
("warn", 1),
("info", 2),
("warn", 3),
("info", 4),
("warn", 5),
("info", 6),
("warn", 7),
("info", 8),
("warn", 9),
("info", 10),
("warn", 11),
("info", 12),
("warn", 13),
("info", 14),
("warn", 15),
("info", 16),
("warn", 17),
("info", 18),
("warn", 19),
] {
Event::create()
.kind(kind)
.timestamp(ts)
.exec(&mut db)
.await?;
}
let events: Vec<_> = Event::filter(Event::fields().timestamp().gt(12))
.exec(&mut db)
.await?;
assert_eq_unordered!(
events.iter().map(|event| event.timestamp),
[&13, &14, &15, &16, &17, &18, &19,]
);
let events: Vec<_> = Event::filter(
Event::fields()
.timestamp()
.gt(12)
.and(Event::fields().kind().ne("info")),
)
.exec(&mut db)
.await?;
assert!(events.iter().all(|event| event.kind != "info"));
assert_eq_unordered!(
events.iter().map(|event| event.timestamp),
[&13, &15, &17, &19,]
);
let events: Vec<_> = Event::filter(
Event::fields()
.kind()
.eq("info")
.and(Event::fields().timestamp().ne(10)),
)
.exec(&mut db)
.await?;
assert_eq_unordered!(
events.iter().map(|event| event.timestamp),
[&0, &2, &4, &6, &8, &12, &14, &16, &18,]
);
let events: Vec<_> = Event::filter(
Event::fields()
.kind()
.eq("info")
.and(Event::fields().timestamp().gt(10)),
)
.exec(&mut db)
.await?;
assert_eq_unordered!(
events.iter().map(|event| event.timestamp),
[&12, &14, &16, &18,]
);
let events: Vec<_> = Event::filter(
Event::fields()
.kind()
.eq("info")
.and(Event::fields().timestamp().ge(10)),
)
.exec(&mut db)
.await?;
assert_eq_unordered!(
events.iter().map(|event| event.timestamp),
[&10, &12, &14, &16, &18,]
);
let events: Vec<_> = Event::filter(
Event::fields()
.kind()
.eq("info")
.and(Event::fields().timestamp().lt(10)),
)
.exec(&mut db)
.await?;
assert_eq_unordered!(
events.iter().map(|event| event.timestamp),
[&0, &2, &4, &6, &8]
);
let events: Vec<_> = Event::filter(
Event::fields()
.kind()
.eq("info")
.and(Event::fields().timestamp().le(10)),
)
.exec(&mut db)
.await?;
assert_eq_unordered!(
events.iter().map(|event| event.timestamp),
[&0, &2, &4, &6, &8, &10]
);
Ok(())
}
#[driver_test(id(ID))]
pub async fn query_not_basic(test: &mut Test) -> Result<()> {
#[derive(Debug, toasty::Model)]
struct User {
#[key]
#[auto]
id: ID,
name: String,
#[allow(dead_code)]
age: i64,
}
let mut db = test.setup_db(models!(User)).await;
for (name, age) in [("Alice", 25), ("Bob", 30), ("Charlie", 35), ("Diana", 40)] {
User::create().name(name).age(age).exec(&mut db).await?;
}
test.log().clear();
let result = User::filter(User::fields().name().eq("Alice").not())
.exec(&mut db)
.await;
if test.capability().sql {
let users = result?;
assert_eq!(3, users.len());
let mut names: Vec<_> = users.iter().map(|u| u.name.as_str()).collect();
names.sort();
assert_eq!(names, ["Bob", "Charlie", "Diana"]);
} else {
assert!(
result.is_err(),
"Expected error for NOT query without key condition on non-SQL database"
);
}
Ok(())
}
#[driver_test(id(ID))]
pub async fn query_not_and_combined(test: &mut Test) -> Result<()> {
#[derive(Debug, toasty::Model)]
struct User {
#[key]
#[auto]
id: ID,
name: String,
#[allow(dead_code)]
age: i64,
#[allow(dead_code)]
active: bool,
}
let mut db = test.setup_db(models!(User)).await;
for (name, age, active) in [
("Alice", 25, true),
("Bob", 30, false),
("Charlie", 35, true),
("Diana", 40, false),
("Eve", 25, false),
] {
User::create()
.name(name)
.age(age)
.active(active)
.exec(&mut db)
.await?;
}
let result = User::filter(
User::fields()
.active()
.eq(true)
.and(User::fields().age().eq(25).not()),
)
.exec(&mut db)
.await;
if test.capability().sql {
let users = result?;
assert_eq!(1, users.len());
assert_eq!("Charlie", users[0].name);
} else {
assert!(
result.is_err(),
"Expected error for NOT query without key condition on non-SQL database"
);
}
Ok(())
}
#[driver_test(id(ID))]
pub async fn query_not_or_combined(test: &mut Test) -> Result<()> {
#[derive(Debug, toasty::Model)]
struct User {
#[key]
#[auto]
id: ID,
name: String,
#[allow(dead_code)]
age: i64,
}
let mut db = test.setup_db(models!(User)).await;
for (name, age) in [("Alice", 25), ("Bob", 30), ("Charlie", 35), ("Diana", 40)] {
User::create().name(name).age(age).exec(&mut db).await?;
}
let result = User::filter(
User::fields()
.name()
.eq("Alice")
.or(User::fields().name().eq("Bob"))
.not(),
)
.exec(&mut db)
.await;
if test.capability().sql {
let users = result?;
assert_eq!(2, users.len());
let mut names: Vec<_> = users.iter().map(|u| u.name.as_str()).collect();
names.sort();
assert_eq!(names, ["Charlie", "Diana"]);
} else {
assert!(
result.is_err(),
"Expected error for NOT query without key condition on non-SQL database"
);
}
Ok(())
}
#[driver_test(id(ID))]
pub async fn query_not_with_index(test: &mut Test) -> Result<()> {
#[derive(Debug, toasty::Model)]
#[key(partition = team, local = name)]
struct Player {
team: String,
name: String,
#[allow(dead_code)]
position: String,
#[allow(dead_code)]
number: i64,
}
let mut db = test.setup_db(models!(Player)).await;
for (team, name, position, number) in [
("Timbers", "Diego Valeri", "Midfielder", 8),
("Timbers", "Darlington Nagbe", "Midfielder", 6),
("Timbers", "Diego Chara", "Midfielder", 21),
("Timbers", "Fanendo Adi", "Forward", 9),
("Timbers", "Adam Kwarasey", "Goalkeeper", 1),
("Sounders", "Clint Dempsey", "Forward", 2),
("Sounders", "Obafemi Martins", "Forward", 9),
("Sounders", "Osvaldo Alonso", "Midfielder", 6),
] {
Player::create()
.team(team)
.name(name)
.position(position)
.number(number)
.exec(&mut db)
.await?;
}
let players = Player::filter(
Player::fields()
.team()
.eq("Timbers")
.and(Player::fields().position().eq("Midfielder").not()),
)
.exec(&mut db)
.await?;
assert_eq!(2, players.len());
let mut names: Vec<_> = players.iter().map(|p| p.name.as_str()).collect();
names.sort();
assert_eq!(names, ["Adam Kwarasey", "Fanendo Adi"]);
let players = Player::filter(
Player::fields()
.team()
.eq("Timbers")
.and(Player::fields().number().gt(8).not()),
)
.exec(&mut db)
.await?;
assert_eq!(3, players.len());
let mut names: Vec<_> = players.iter().map(|p| p.name.as_str()).collect();
names.sort();
assert_eq!(names, ["Adam Kwarasey", "Darlington Nagbe", "Diego Valeri"]);
Ok(())
}
#[driver_test(id(ID))]
pub async fn query_not_operator_syntax(test: &mut Test) -> Result<()> {
#[derive(Debug, toasty::Model)]
#[key(partition = team, local = name)]
struct Player {
team: String,
name: String,
#[allow(dead_code)]
position: String,
#[allow(dead_code)]
number: i64,
}
let mut db = test.setup_db(models!(Player)).await;
for (team, name, position, number) in [
("Timbers", "Diego Valeri", "Midfielder", 8),
("Timbers", "Darlington Nagbe", "Midfielder", 6),
("Timbers", "Diego Chara", "Midfielder", 21),
("Timbers", "Fanendo Adi", "Forward", 9),
("Timbers", "Adam Kwarasey", "Goalkeeper", 1),
] {
Player::create()
.team(team)
.name(name)
.position(position)
.number(number)
.exec(&mut db)
.await?;
}
let players = Player::filter(
Player::fields()
.team()
.eq("Timbers")
.and(!Player::fields().position().eq("Midfielder")),
)
.exec(&mut db)
.await?;
assert_eq!(2, players.len());
let mut names: Vec<_> = players.iter().map(|p| p.name.as_str()).collect();
names.sort();
assert_eq!(names, ["Adam Kwarasey", "Fanendo Adi"]);
let players = Player::filter(
Player::fields().team().eq("Timbers").and(
!(Player::fields()
.number()
.gt(8)
.or(Player::fields().position().eq("Goalkeeper"))),
),
)
.exec(&mut db)
.await?;
assert_eq!(2, players.len());
let mut names: Vec<_> = players.iter().map(|p| p.name.as_str()).collect();
names.sort();
assert_eq!(names, ["Darlington Nagbe", "Diego Valeri"]);
Ok(())
}