mirror of
https://github.com/aljazceru/turso.git
synced 2026-01-28 12:24:23 +01:00
Merge 'cli: added .tables command' from Konstantinos Artopoulos
This PR adds the `.tables` command. I use it a lot in sqlite and I noticed it was missing from here so I decided to contribute. Let me know if any changes or improvements are required. Reviewed-by: Preston Thorpe <alpkeles99@gmail.com> Closes #503
This commit is contained in:
82
cli/app.rs
82
cli/app.rs
@@ -76,6 +76,8 @@ pub enum Command {
|
||||
NullValue,
|
||||
/// Toggle 'echo' mode to repeat commands before execution
|
||||
Echo,
|
||||
/// Display tables
|
||||
Tables,
|
||||
}
|
||||
|
||||
impl Command {
|
||||
@@ -86,6 +88,7 @@ impl Command {
|
||||
| Self::Help
|
||||
| Self::Opcodes
|
||||
| Self::ShowInfo
|
||||
| Self::Tables
|
||||
| Self::SetOutput => 0,
|
||||
Self::Open | Self::OutputMode | Self::Cwd | Self::Echo | Self::NullValue => 1,
|
||||
} + 1) // argv0
|
||||
@@ -104,6 +107,7 @@ impl Command {
|
||||
Self::ShowInfo => ".show",
|
||||
Self::NullValue => ".nullvalue <string>",
|
||||
Self::Echo => ".echo on|off",
|
||||
Self::Tables => ".tables",
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -116,6 +120,7 @@ impl FromStr for Command {
|
||||
".open" => Ok(Self::Open),
|
||||
".help" => Ok(Self::Help),
|
||||
".schema" => Ok(Self::Schema),
|
||||
".tables" => Ok(Self::Tables),
|
||||
".opcodes" => Ok(Self::Opcodes),
|
||||
".mode" => Ok(Self::OutputMode),
|
||||
".output" => Ok(Self::SetOutput),
|
||||
@@ -421,6 +426,12 @@ impl Limbo {
|
||||
let _ = self.writeln(e.to_string());
|
||||
}
|
||||
}
|
||||
Command::Tables => {
|
||||
let pattern = args.get(1).copied();
|
||||
if let Err(e) = self.display_tables(pattern) {
|
||||
let _ = self.writeln(e.to_string());
|
||||
}
|
||||
}
|
||||
Command::Opcodes => {
|
||||
if args.len() > 1 {
|
||||
for op in &OPCODE_DESCRIPTIONS {
|
||||
@@ -621,6 +632,63 @@ impl Limbo {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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 '{}' ORDER BY 1",
|
||||
pattern
|
||||
),
|
||||
None => String::from(
|
||||
"SELECT name FROM sqlite_schema WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY 1"
|
||||
),
|
||||
};
|
||||
|
||||
match self.conn.query(&sql) {
|
||||
Ok(Some(ref mut rows)) => {
|
||||
let mut tables = String::new();
|
||||
loop {
|
||||
match rows.next_row()? {
|
||||
RowResult::Row(row) => {
|
||||
if let Some(Value::Text(table)) = row.values.first() {
|
||||
tables.push_str(table);
|
||||
tables.push(' ');
|
||||
}
|
||||
}
|
||||
RowResult::IO => {
|
||||
self.io.run_once()?;
|
||||
}
|
||||
RowResult::Done => break,
|
||||
}
|
||||
}
|
||||
|
||||
if tables.len() > 0 {
|
||||
let _ = self.writeln(tables.trim_end());
|
||||
} else {
|
||||
if let Some(pattern) = pattern {
|
||||
let _ = self.write_fmt(format_args!(
|
||||
"Error: Tables with pattern '{}' not found.",
|
||||
pattern
|
||||
));
|
||||
} else {
|
||||
let _ = self.writeln("No tables found in the database.");
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(None) => {
|
||||
let _ = self.writeln("No results returned from the query.");
|
||||
}
|
||||
Err(err) => {
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn get_writer(output: &str) -> Box<dyn Write> {
|
||||
@@ -656,6 +724,7 @@ Special Commands:
|
||||
.open <database_file> Open and connect to a database file.
|
||||
.output <mode> Change the output mode. Available modes are 'raw' and 'pretty'.
|
||||
.schema <table_name> Show the schema of the specified table.
|
||||
.tables <pattern> List names of tables matching LIKE pattern TABLE
|
||||
.opcodes Display all the opcodes defined by the virtual machine
|
||||
.cd <directory> Change the current working directory.
|
||||
.nullvalue <string> Set the value to be displayed for null values.
|
||||
@@ -673,19 +742,22 @@ Usage Examples:
|
||||
3. To view the schema of a table named 'employees':
|
||||
.schema employees
|
||||
|
||||
4. To list all available SQL opcodes:
|
||||
4. To list all tables:
|
||||
.tables
|
||||
|
||||
5. To list all available SQL opcodes:
|
||||
.opcodes
|
||||
|
||||
5. To change the current output mode to 'pretty':
|
||||
6. To change the current output mode to 'pretty':
|
||||
.mode pretty
|
||||
|
||||
6. Send output to STDOUT if no file is specified:
|
||||
7. Send output to STDOUT if no file is specified:
|
||||
.output
|
||||
|
||||
7. To change the current working directory to '/tmp':
|
||||
8. To change the current working directory to '/tmp':
|
||||
.cd /tmp
|
||||
|
||||
8. Show the current values of settings:
|
||||
9. Show the current values of settings:
|
||||
.show
|
||||
|
||||
Note:
|
||||
|
||||
@@ -95,3 +95,8 @@ do_execsql_test_on_specific_db testing/testing.db schema-2 {
|
||||
# name TEXT,
|
||||
# price REAL
|
||||
# );"}
|
||||
|
||||
# FIXME sqlite uses multicolumn output mode for display resulting in different spacing
|
||||
# do_execsql_test_on_specific_db testing/testing.db schema-1 {
|
||||
# .tables
|
||||
# } {"products users"}
|
||||
|
||||
@@ -182,6 +182,11 @@ Null value: LIMBO
|
||||
CWD: {cwd}/testing
|
||||
Echo: off""",
|
||||
)
|
||||
|
||||
do_execshell_test(pipe, "test-show-tables", ".tables", "products users")
|
||||
|
||||
do_execshell_test(pipe, "test-show-tables-with-pattern", ".tables us%", "users")
|
||||
|
||||
# test we can set the null value
|
||||
|
||||
write_to_pipe(".open :memory:")
|
||||
|
||||
Reference in New Issue
Block a user