Skip to main content

sqlx_gen/introspect/
sqlite.rs

1use crate::error::Result;
2use sqlx::SqlitePool;
3
4use super::{ColumnInfo, SchemaInfo, TableInfo};
5
6pub async fn introspect(pool: &SqlitePool, include_views: bool) -> Result<SchemaInfo> {
7    let tables = fetch_tables(pool).await?;
8    let views = if include_views {
9        fetch_views(pool).await?
10    } else {
11        Vec::new()
12    };
13
14    Ok(SchemaInfo {
15        tables,
16        views,
17        enums: Vec::new(),
18        composite_types: Vec::new(),
19        domains: Vec::new(),
20    })
21}
22
23async fn fetch_tables(pool: &SqlitePool) -> Result<Vec<TableInfo>> {
24    let table_names: Vec<(String,)> = sqlx::query_as(
25        "SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%' ORDER BY name",
26    )
27    .fetch_all(pool)
28    .await?;
29
30    let mut tables = Vec::new();
31
32    for (table_name,) in table_names {
33        let columns = fetch_columns(pool, &table_name).await?;
34        tables.push(TableInfo {
35            schema_name: "main".to_string(),
36            name: table_name,
37            columns,
38        });
39    }
40
41    Ok(tables)
42}
43
44async fn fetch_views(pool: &SqlitePool) -> Result<Vec<TableInfo>> {
45    let view_names: Vec<(String,)> = sqlx::query_as(
46        "SELECT name FROM sqlite_master WHERE type = 'view' ORDER BY name",
47    )
48    .fetch_all(pool)
49    .await?;
50
51    let mut views = Vec::new();
52
53    for (view_name,) in view_names {
54        let columns = fetch_columns(pool, &view_name).await?;
55        views.push(TableInfo {
56            schema_name: "main".to_string(),
57            name: view_name,
58            columns,
59        });
60    }
61
62    Ok(views)
63}
64
65async fn fetch_columns(pool: &SqlitePool, table_name: &str) -> Result<Vec<ColumnInfo>> {
66    // PRAGMA table_info returns: cid, name, type, notnull, dflt_value, pk
67    let pragma_query = format!("PRAGMA table_info(\"{}\")", table_name.replace('"', "\"\""));
68    let rows: Vec<(i32, String, String, bool, Option<String>, i32)> =
69        sqlx::query_as(&pragma_query).fetch_all(pool).await?;
70
71    Ok(rows
72        .into_iter()
73        .map(|(cid, name, declared_type, notnull, dflt_value, pk)| {
74            let upper = declared_type.to_uppercase();
75            ColumnInfo {
76                name,
77                data_type: upper.clone(),
78                udt_name: upper,
79                is_nullable: !notnull,
80                is_primary_key: pk > 0,
81                ordinal_position: cid,
82                schema_name: "main".to_string(),
83                column_default: dflt_value,
84            }
85        })
86        .collect())
87}