Skip to content

Commit

Permalink
v1.0.199
Browse files Browse the repository at this point in the history
  • Loading branch information
yy0931 committed Dec 30, 2024
1 parent 850cda1 commit c00097d
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 44 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "sqlite3-editor"
version = "1.0.197"
version = "1.0.199"
edition = "2021"

[features]
Expand Down
4 changes: 2 additions & 2 deletions src/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ pub fn export_csv<W: Write>(
.prepare(query)
.or_else(|err| Error::new_query_error(err, query, &[]))?;

if options.delimiter.as_bytes().len() != 1 {
Error::new_other_error("The delimiter needs to be a single character.", None, None)?;
if options.delimiter.len() != 1 {
Error::new_other_error("The delimiter needs to be a single-byte character.", None, None)?;
}

// TODO: `stmt.column_count()` and `stmt.column_names()` should be called after `rows.next()` (see https://github.com/rusqlite/rusqlite/blob/b7309f2dca70716fee44c85082c585b330edb073/src/column.rs#L51-L53).
Expand Down
2 changes: 1 addition & 1 deletion src/export_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ fn test_invalid_delimiter() {
)
.unwrap_err()
.to_string()
.contains("The delimiter needs to be a single character."));
.contains("The delimiter needs to be a single-byte character."));
}

#[test]
Expand Down
52 changes: 18 additions & 34 deletions src/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,34 +106,16 @@ pub fn import_json(
table_name: &str,
input_file: Option<String>,
) -> std::result::Result<(), Error> {
use serde_json::Value;

let parsed: Vec<HashMap<String, String>> =
serde_json::from_reader::<_, Vec<HashMap<String, Value>>>(open_reader(input_file)?)?
.into_iter()
.map(|map| {
map.into_iter()
.map(|(k, v)| {
(
k,
match v {
Value::String(s) => s,
v => v.to_string(),
},
)
})
.collect()
})
.collect();
let parsed = serde_json::from_reader::<_, Vec<HashMap<String, Literal>>>(open_reader(input_file)?)?;

if parsed.is_empty() {
Error::new_other_error("No data present.", None, None)?;
return Error::new_other_error("No data present.", None, None);
}

let columns = parsed.first().unwrap().keys().map(|v| v.to_owned()).collect::<Vec<_>>();

if columns.is_empty() {
Error::new_other_error("No column headers present.", None, None)?;
return Error::new_other_error("No column headers present.", None, None);
}

let mut con = connect(database_filepath, sql_cipher_key)?;
Expand All @@ -145,7 +127,7 @@ pub fn import_json(
escape_sql_identifier(table_name),
columns
.iter()
.map(|v| format!("{} TEXT", escape_sql_identifier(v)))
.map(|v| escape_sql_identifier(v))
.collect::<Vec<_>>()
.join(", ")
);
Expand All @@ -165,23 +147,25 @@ pub fn import_json(
let mut insert = tx
.prepare(&stmt)
.or_else(|err| Error::new_query_error(err, &stmt, &[]))?;
for record in &parsed {
let values = columns.iter().map(|column| record.get(column)).collect::<Vec<_>>();
for (record_id, record) in parsed.iter().enumerate() {
let mut values = Vec::<&Literal>::new();
for column in &columns {
let Some(value) = record.get(column) else {
return Error::new_other_error(
format!("The row {} does not have the column '{column}'.", record_id + 1),
None,
None,
);
};
values.push(value);
}
for (i, value) in values.iter().enumerate() {
insert.raw_bind_parameter(i + 1, value).or_else(|err| {
Error::new_query_error(
err,
&stmt,
&values.iter().map(|v| (*v).into()).collect::<Vec<Literal>>(),
)
Error::new_query_error(err, &stmt, &values.iter().map(|&v| v.clone()).collect::<Vec<Literal>>())
})?;
}
insert.raw_execute().or_else(|err| {
Error::new_query_error(
err,
&stmt,
&values.iter().map(|v| (*v).into()).collect::<Vec<Literal>>(),
)
Error::new_query_error(err, &stmt, &values.iter().map(|&v| v.clone()).collect::<Vec<Literal>>())
})?;
}
}
Expand Down
18 changes: 14 additions & 4 deletions src/import_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,11 @@ fn test_import_json() {
let tmp_json_file_path = tmp_json_file.path().to_str().unwrap().to_owned();

// Write a sample JSON file to import.
fs::write(&tmp_json_file, r#"[{"name":"Alice","age":20},{"name":"Bob","age":25}]"#).unwrap();
fs::write(
&tmp_json_file,
r#"[{"name":"Alice","age":20,"optional":null},{"name":"Bob","age":25,"optional":0}]"#,
)
.unwrap();

// Import the JSON file.
assert!(import::import_json(tmp_db_filepath, &None, "test", Some(tmp_json_file_path)).is_ok());
Expand All @@ -137,17 +141,23 @@ fn test_import_json() {
let result = serde_json::to_string(
&rusqlite::Connection::open(tmp_db_filepath)
.unwrap()
.prepare("SELECT * FROM test")
.prepare("SELECT name, age, optional FROM test")
.unwrap()
.query_map([], |row| Ok((get_string(row, 0, |_| {})?, get_string(row, 1, |_| {})?)))
.query_map([], |row| {
Ok((
row.get::<_, String>(0)?,
row.get::<_, i32>(1)?,
row.get::<_, Option<i32>>(2)?,
))
})
.unwrap()
.collect::<Result<Vec<_>, _>>()
.unwrap(),
)
.unwrap();

// key orders are not maintained
assert!(result == r#"[["Alice","20"],["Bob","25"]]"# || result == r#"[["20","Alice"],["25","Bob"]]"#);
assert_eq!(result, r#"[["Alice",20,null],["Bob",25,0]]"#);
}

#[test]
Expand Down

0 comments on commit c00097d

Please sign in to comment.