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