tank_tests/
readme.rs

1use std::{borrow::Cow, collections::HashSet, sync::LazyLock};
2use tank::{Entity, Executor, Result, expr, stream::TryStreamExt};
3use tokio::sync::Mutex;
4
5#[derive(Entity)]
6#[tank(schema = "army")]
7pub struct Tank {
8    #[tank(primary_key)]
9    pub name: String,
10    pub country: Cow<'static, str>,
11    #[tank(name = "caliber")]
12    pub caliber_mm: u16,
13    #[tank(name = "speed")]
14    pub speed_kmh: f32,
15    pub is_operational: bool,
16    pub units_produced: Option<u32>,
17}
18static MUTEX: LazyLock<Mutex<()>> = LazyLock::new(|| Mutex::new(()));
19
20pub async fn readme<E: Executor>(connection: &mut E) -> Result<()> {
21    let _lock = MUTEX.lock();
22
23    let my_tank = Tank {
24        name: "Tiger I".into(),
25        country: "Germany".into(),
26        caliber_mm: 88,
27        speed_kmh: 45.4,
28        is_operational: false,
29        units_produced: Some(1_347),
30    };
31
32    /*
33     * DROP TABLE IF EXISTS "army"."tank";
34     */
35    Tank::drop_table(connection, true, false).await?;
36
37    /*
38     * CREATE SCHEMA IF NOT EXISTS "army";
39     * CREATE TABLE IF NOT EXISTS "army"."tank" (
40     *     "name" VARCHAR PRIMARY KEY,
41     *     "country" VARCHAR NOT NULL,
42     *     "caliber" USMALLINT NOT NULL,
43     *     "speed" FLOAT NOT NULL,
44     *     "is_operational" BOOLEAN NOT NULL,
45     *     "units_produced" UINTEGER);
46     */
47    Tank::create_table(connection, true, true).await?;
48
49    /*
50     * INSERT INTO "army"."tank" ("name", "country", "caliber", "speed", "is_operational", "units_produced") VALUES
51     *     ('Tiger I', 'Germany', 88, 45.4, false, 1347)
52     * ON CONFLICT ("name") DO UPDATE SET
53     *     "country" = EXCLUDED."country",
54     *     "caliber" = EXCLUDED."caliber",
55     *     "speed" = EXCLUDED."speed",
56     *     "is_operational" = EXCLUDED."is_operational",
57     *     "units_produced" = EXCLUDED."units_produced";
58     */
59    my_tank.save(connection).await?;
60
61    /*
62     * In the case of DuckDB, it uses the appender API, in other cases the resulting query is:
63     * INSERT INTO "army"."tank" ("name", "country", "caliber", "speed", "is_operational", "units_produced") VALUES
64     *     ('T-34/85', 'Soviet Union', 85, 53.0, false, 49200),
65     *     ('M1 Abrams', 'USA', 120, 72.0, true, NULL);
66     */
67    Tank::insert_many(
68        connection,
69        &[
70            Tank {
71                name: "T-34/85".into(),
72                country: "Soviet Union".into(),
73                caliber_mm: 85,
74                speed_kmh: 53.0,
75                is_operational: false,
76                units_produced: Some(49_200),
77            },
78            Tank {
79                name: "M1 Abrams".into(),
80                country: "USA".into(),
81                caliber_mm: 120,
82                speed_kmh: 72.0,
83                is_operational: true,
84                units_produced: None,
85            },
86        ],
87    )
88    .await?;
89
90    /*
91     * SELECT "name", "country", "caliber", "speed", "is_operational", "units_produced"
92     * FROM "army"."tank"
93     * WHERE "is_operational" = false
94     * LIMIT 1000;
95     */
96    let tanks = Tank::find_many(
97        connection,
98        &expr!(Tank::is_operational == false),
99        Some(1000),
100    )
101    .try_collect::<Vec<_>>()
102    .await?;
103
104    assert_eq!(
105        tanks
106            .iter()
107            .map(|t| t.name.to_string())
108            .collect::<HashSet<_>>(),
109        HashSet::from_iter(["Tiger I".into(), "T-34/85".into()])
110    );
111    Ok(())
112}