feat(usable): integrate current dbtool implementation snapshot
Some checks failed
release-smoke / macos-13 / x86_64-apple-darwin (push) Has been cancelled
release-smoke / ubuntu-latest / x86_64-unknown-linux-gnu (push) Has been cancelled
release-smoke / windows-latest / x86_64-pc-windows-msvc (push) Has been cancelled

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Paperclip CTO
2026-04-02 08:26:18 +00:00
parent a28dab4cd9
commit d5f69462b0
73 changed files with 5895 additions and 322 deletions

View File

@@ -102,23 +102,27 @@ impl DatabaseDriver for PostgresDriver {
(None, None) => {
let rows = client
.query(
"SELECT schema_name \
FROM information_schema.schemata \
WHERE schema_name NOT IN ('pg_catalog', 'information_schema') \
ORDER BY schema_name",
"SELECT n.nspname AS schema_name,
has_schema_privilege(n.nspname, 'USAGE') AS has_usage
FROM pg_namespace n
WHERE n.nspname NOT IN ('pg_catalog', 'information_schema')
AND n.nspname NOT LIKE 'pg_toast%'
AND n.nspname NOT LIKE 'pg_temp_%'
ORDER BY n.nspname",
&[],
)
.map_err(map_postgres_error)?;
Ok(InspectResult::Schemas(
rows.into_iter()
.map(|row| SchemaSummary {
name: row.get::<_, String>(0),
.map(|row| {
postgres_schema_summary(row.get::<_, String>(0), row.get::<_, bool>(1))
})
.collect(),
))
}
(Some(schema), None) => {
ensure_postgres_schema_access(&mut client, schema)?;
let rows = client
.query(
"SELECT table_schema, table_name, table_type \
@@ -140,6 +144,7 @@ impl DatabaseDriver for PostgresDriver {
))
}
(Some(schema), Some(table)) => {
ensure_postgres_schema_access(&mut client, schema)?;
let rows = client
.query(
"SELECT c.column_name,
@@ -256,7 +261,7 @@ impl DatabaseDriver for MysqlDriver {
Ok(InspectResult::Schemas(
rows.into_iter()
.map(|(name,)| SchemaSummary { name })
.map(|(name,)| SchemaSummary::ready(name))
.collect(),
))
}
@@ -516,11 +521,7 @@ fn inspect_sqlite_schemas(connection: &SqliteConnection) -> Result<InspectResult
.prepare("PRAGMA database_list")
.map_err(map_sqlite_inspect_error)?;
let schemas = statement
.query_map([], |row| {
Ok(SchemaSummary {
name: row.get::<_, String>(1)?,
})
})
.query_map([], |row| Ok(SchemaSummary::ready(row.get::<_, String>(1)?)))
.map_err(map_sqlite_inspect_error)?
.collect::<rusqlite::Result<Vec<_>>>()
.map_err(map_sqlite_inspect_error)?;
@@ -651,6 +652,41 @@ fn simple_query_result(client: &mut Client, sql: &str) -> Result<QueryResult, Dr
}
}
fn postgres_schema_summary(name: String, has_usage: bool) -> SchemaSummary {
if has_usage {
SchemaSummary::ready(name)
} else {
SchemaSummary::restricted(name.clone(), restricted_schema_message(&name))
}
}
fn ensure_postgres_schema_access(client: &mut Client, schema: &str) -> Result<(), DriverError> {
let row = client
.query_one(
"SELECT EXISTS (
SELECT 1
FROM pg_namespace
WHERE nspname = $1
) AS schema_exists,
has_schema_privilege($1, 'USAGE') AS has_usage",
&[&schema],
)
.map_err(map_postgres_error)?;
let schema_exists = row.get::<_, bool>(0);
let has_usage = row.get::<_, bool>(1);
if schema_exists && !has_usage {
return Err(DriverError::Inspect(restricted_schema_message(schema)));
}
Ok(())
}
fn restricted_schema_message(schema: &str) -> String {
format!("schema access is restricted: {schema}")
}
fn consume_mysql_query_result<T: MySqlProtocol>(
mut result: MySqlQueryResult<'_, '_, '_, T>,
) -> Result<QueryResult, DriverError> {
@@ -964,6 +1000,27 @@ mod tests {
assert_eq!(rendered, "张敏😀");
}
#[test]
fn postgres_schema_summary_marks_restricted_entries() {
let schema = postgres_schema_summary(String::from("restricted_probe"), false);
assert_eq!(
schema,
SchemaSummary::restricted(
"restricted_probe",
"schema access is restricted: restricted_probe"
)
);
}
#[test]
fn restricted_schema_message_is_stable() {
assert_eq!(
restricted_schema_message("restricted_probe"),
"schema access is restricted: restricted_probe"
);
}
#[test]
fn sqlite_driver_supports_connect_inspect_and_query() {
let unique = SystemTime::now()
@@ -995,9 +1052,7 @@ mod tests {
.expect("sqlite schemas should load");
assert_eq!(
schemas,
InspectResult::Schemas(vec![SchemaSummary {
name: String::from("main"),
}])
InspectResult::Schemas(vec![SchemaSummary::ready("main")])
);
let tables = DriverRegistry::inspect(