Skip to main content

nu_command/stor/
export.rs

1use crate::database::{MEMORY_DB, SQLiteDatabase};
2use nu_engine::command_prelude::*;
3use nu_protocol::Signals;
4use nu_protocol::shell_error::generic::GenericError;
5
6#[derive(Clone)]
7pub struct StorExport;
8
9impl Command for StorExport {
10    fn name(&self) -> &str {
11        "stor export"
12    }
13
14    fn signature(&self) -> Signature {
15        Signature::build("stor export")
16            .input_output_types(vec![(Type::Nothing, Type::table())])
17            .required_named(
18                "file-name",
19                SyntaxShape::String,
20                "File name to export the sqlite in-memory database to.",
21                Some('f'),
22            )
23            .allow_variants_without_examples(true)
24            .category(Category::Database)
25    }
26
27    fn description(&self) -> &str {
28        "Export the in-memory sqlite database to a sqlite database file."
29    }
30
31    fn search_terms(&self) -> Vec<&str> {
32        vec!["sqlite", "save", "database", "saving", "file"]
33    }
34
35    fn examples(&self) -> Vec<Example<'_>> {
36        vec![Example {
37            description: "Export the in-memory sqlite database",
38            example: "stor export --file-name nudb.sqlite",
39            result: None,
40        }]
41    }
42
43    fn run(
44        &self,
45        engine_state: &EngineState,
46        stack: &mut Stack,
47        call: &Call,
48        _input: PipelineData,
49    ) -> Result<PipelineData, ShellError> {
50        let span = call.head;
51        let file_name_opt: Option<String> = call.get_flag(engine_state, stack, "file-name")?;
52        let file_name = match file_name_opt {
53            Some(file_name) => file_name,
54            None => {
55                return Err(ShellError::MissingParameter {
56                    param_name: "please supply a file name with the --file-name parameter".into(),
57                    span,
58                });
59            }
60        };
61
62        // Open the in-mem database
63        let db = Box::new(SQLiteDatabase::new(
64            std::path::Path::new(MEMORY_DB),
65            Signals::empty(),
66        ));
67
68        if let Ok(conn) = db.open_connection() {
69            // This uses vacuum. I'm not really sure if this is the best way to do this.
70            // I also added backup in the sqlitedatabase impl. If we have problems, we could switch to that.
71            db.export_in_memory_database_to_file(&conn, file_name)
72                .map_err(|err| {
73                    ShellError::Generic(GenericError::new_internal(
74                        "Failed to open SQLite connection in memory from export",
75                        err.to_string(),
76                    ))
77                })?;
78        }
79        // dbg!(db.clone());
80        Ok(Value::custom(db, span).into_pipeline_data())
81    }
82}
83
84#[cfg(test)]
85mod test {
86    use super::*;
87
88    #[test]
89    fn test_examples() -> nu_test_support::Result {
90        nu_test_support::test().examples(StorExport)
91    }
92}