mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-01 22:34:22 +01:00
Merge 'cli: .tables and .indexes to show data from attached tables aswell' from Konstantinos Artopoulos
Closes #3545 Reviewed-by: Preston Thorpe <preston@turso.tech> Closes #3627
This commit is contained in:
109
cli/app.rs
109
cli/app.rs
@@ -1239,26 +1239,33 @@ impl Limbo {
|
||||
}
|
||||
|
||||
fn display_indexes(&mut self, maybe_table: Option<String>) -> anyhow::Result<()> {
|
||||
let sql = match maybe_table {
|
||||
Some(ref tbl_name) => format!(
|
||||
"SELECT name FROM sqlite_schema WHERE type='index' AND tbl_name = '{tbl_name}' ORDER BY 1"
|
||||
),
|
||||
None => String::from("SELECT name FROM sqlite_schema WHERE type='index' ORDER BY 1"),
|
||||
};
|
||||
|
||||
let mut indexes = String::new();
|
||||
let handler = |row: &turso_core::Row| -> anyhow::Result<()> {
|
||||
if let Ok(Value::Text(idx)) = row.get::<&Value>(0) {
|
||||
indexes.push_str(idx.as_str());
|
||||
indexes.push(' ');
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
if let Err(err) = self.handle_row(&sql, handler) {
|
||||
if err.to_string().contains("no such table: sqlite_schema") {
|
||||
return Err(anyhow::anyhow!("Unable to access database schema. The database may be using an older SQLite version or may not be properly initialized."));
|
||||
} else {
|
||||
return Err(anyhow::anyhow!("Error querying schema: {}", err));
|
||||
|
||||
for name in self.database_names()? {
|
||||
let prefix = (name != "main").then_some(&name);
|
||||
let sql = match maybe_table {
|
||||
Some(ref tbl_name) => format!(
|
||||
"SELECT name FROM {name}.sqlite_schema WHERE type='index' AND tbl_name = '{tbl_name}' ORDER BY 1"
|
||||
),
|
||||
None => format!("SELECT name FROM {name}.sqlite_schema WHERE type='index' ORDER BY 1"),
|
||||
};
|
||||
let handler = |row: &turso_core::Row| -> anyhow::Result<()> {
|
||||
if let Ok(Value::Text(idx)) = row.get::<&Value>(0) {
|
||||
if let Some(prefix) = prefix {
|
||||
indexes.push_str(prefix);
|
||||
indexes.push('.');
|
||||
}
|
||||
indexes.push_str(idx.as_str());
|
||||
indexes.push(' ');
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
if let Err(err) = self.handle_row(&sql, handler) {
|
||||
if err.to_string().contains("no such table: sqlite_schema") {
|
||||
return Err(anyhow::anyhow!("Unable to access database schema. The database may be using an older SQLite version or may not be properly initialized."));
|
||||
} else {
|
||||
return Err(anyhow::anyhow!("Error querying schema: {}", err));
|
||||
}
|
||||
}
|
||||
}
|
||||
if !indexes.is_empty() {
|
||||
@@ -1268,28 +1275,35 @@ impl Limbo {
|
||||
}
|
||||
|
||||
fn display_tables(&mut self, pattern: Option<&str>) -> anyhow::Result<()> {
|
||||
let sql = match pattern {
|
||||
Some(pattern) => format!(
|
||||
"SELECT name FROM sqlite_schema WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name LIKE '{pattern}' ORDER BY 1"
|
||||
),
|
||||
None => String::from(
|
||||
"SELECT name FROM sqlite_schema WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY 1"
|
||||
),
|
||||
};
|
||||
|
||||
let mut tables = String::new();
|
||||
let handler = |row: &turso_core::Row| -> anyhow::Result<()> {
|
||||
if let Ok(Value::Text(table)) = row.get::<&Value>(0) {
|
||||
tables.push_str(table.as_str());
|
||||
tables.push(' ');
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
if let Err(e) = self.handle_row(&sql, handler) {
|
||||
if e.to_string().contains("no such table: sqlite_schema") {
|
||||
return Err(anyhow::anyhow!("Unable to access database schema. The database may be using an older SQLite version or may not be properly initialized."));
|
||||
} else {
|
||||
return Err(anyhow::anyhow!("Error querying schema: {}", e));
|
||||
|
||||
for name in self.database_names()? {
|
||||
let prefix = (name != "main").then_some(&name);
|
||||
let sql = match pattern {
|
||||
Some(pattern) => format!(
|
||||
"SELECT name FROM {name}.sqlite_schema WHERE type='table' AND name NOT LIKE 'sqlite_%' AND name LIKE '{pattern}' ORDER BY 1"
|
||||
),
|
||||
None => format!(
|
||||
"SELECT name FROM {name}.sqlite_schema WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY 1"
|
||||
),
|
||||
};
|
||||
let handler = |row: &turso_core::Row| -> anyhow::Result<()> {
|
||||
if let Ok(Value::Text(table)) = row.get::<&Value>(0) {
|
||||
if let Some(prefix) = prefix {
|
||||
tables.push_str(prefix);
|
||||
tables.push('.');
|
||||
}
|
||||
tables.push_str(table.as_str());
|
||||
tables.push(' ');
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
if let Err(e) = self.handle_row(&sql, handler) {
|
||||
if e.to_string().contains("no such table: sqlite_schema") {
|
||||
return Err(anyhow::anyhow!("Unable to access database schema. The database may be using an older SQLite version or may not be properly initialized."));
|
||||
} else {
|
||||
return Err(anyhow::anyhow!("Error querying schema: {}", e));
|
||||
}
|
||||
}
|
||||
}
|
||||
if !tables.is_empty() {
|
||||
@@ -1304,6 +1318,21 @@ impl Limbo {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn database_names(&mut self) -> anyhow::Result<Vec<String>> {
|
||||
let sql = "PRAGMA database_list";
|
||||
let mut db_names: Vec<String> = Vec::new();
|
||||
let handler = |row: &turso_core::Row| -> anyhow::Result<()> {
|
||||
if let Ok(Value::Text(name)) = row.get::<&Value>(1) {
|
||||
db_names.push(name.to_string());
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
match self.handle_row(sql, handler) {
|
||||
Ok(_) => Ok(db_names),
|
||||
Err(e) => Err(anyhow::anyhow!("Error in database list: {}", e)),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_row<F>(&mut self, sql: &str, mut handler: F) -> anyhow::Result<()>
|
||||
where
|
||||
F: FnMut(&turso_core::Row) -> anyhow::Result<()>,
|
||||
|
||||
@@ -157,6 +157,7 @@ def test_output_file():
|
||||
|
||||
# Clean up
|
||||
os.remove(output_file)
|
||||
shell.quit()
|
||||
|
||||
|
||||
def test_multi_line_single_line_comments_succession():
|
||||
@@ -367,6 +368,16 @@ def test_parse_error():
|
||||
lambda res: "Parse error: " in res,
|
||||
"Try to LIMIT using an identifier should trigger a Parse error",
|
||||
)
|
||||
turso.quit()
|
||||
|
||||
|
||||
def test_tables_with_attached_db():
|
||||
shell = TestTursoShell()
|
||||
shell.execute_dot(".open :memory:")
|
||||
shell.execute_dot("CREATE TABLE orders(a);")
|
||||
shell.execute_dot("ATTACH DATABASE 'testing/testing.db' AS attached;")
|
||||
shell.run_test("tables-with-attached-database", ".tables", "orders attached.products attached.users")
|
||||
shell.quit()
|
||||
|
||||
|
||||
def main():
|
||||
@@ -393,6 +404,7 @@ def main():
|
||||
test_copy_db_file()
|
||||
test_copy_memory_db_to_file()
|
||||
test_parse_error()
|
||||
test_tables_with_attached_db()
|
||||
console.info("All tests have passed")
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user