Initial commit: CSV to SQLite push tool
Rust CLI tool to push CSV data (water and car readings) into SQLite database. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
/target
|
||||
data/*.db
|
||||
.DS_Store
|
||||
.idea/
|
||||
53
CLAUDE.md
Normal file
53
CLAUDE.md
Normal file
@@ -0,0 +1,53 @@
|
||||
this project is a tool CLI that can take CSV file and push its content into a sqlite database.
|
||||
|
||||
the CSV files have the following columns:
|
||||
|
||||
- Date
|
||||
- Eau
|
||||
- Scénic
|
||||
- Zoé
|
||||
|
||||
the sqlite databases has been created with the following command:
|
||||
|
||||
CREATE TABLE "eau"
|
||||
(
|
||||
date TEXT not null
|
||||
primary key
|
||||
unique,
|
||||
releve REAL not null,
|
||||
comment TEXT
|
||||
)
|
||||
|
||||
CREATE TABLE "voiture1" (
|
||||
"date" TEXT NOT NULL UNIQUE,
|
||||
"releve" INTEGER NOT NULL,
|
||||
"comment" TEXT,
|
||||
PRIMARY KEY("date")
|
||||
)
|
||||
|
||||
CREATE TABLE "voiture2"
|
||||
(
|
||||
date TEXT not null,
|
||||
releve INTEGER not null,
|
||||
comment TEXT
|
||||
)
|
||||
|
||||
CSV columns "Date" and "Eau" has to be pushed to database table "eau" on columns "date" and "releve". no push if "Eau" is empty
|
||||
CSV columns "Date" and "Scénic" has to be pushed to database table "voiture1" on columns "date" and "releve". no push if "Scénic" is empty
|
||||
CSV columns "Date" and "Zoé" has to be pushed to database table "voiture2" on columns "date" and "releve". no push if "Zoé" is empty
|
||||
|
||||
the CLI takes 2 parameters:
|
||||
|
||||
- first is the name of the CSV file
|
||||
- second is the JDBC URL (for example, "jdbc:sqlite:/Users/kriss/NextCloud/Kriss/Dev/Perso/conso/db/conso.db")
|
||||
|
||||
when launched, the tool checks that:
|
||||
|
||||
- CSV file exists on the disk
|
||||
- CSV file contains exactly the described columns
|
||||
- Sqlite database is accessible through the JDBC URL
|
||||
- Ensure there won't be any duplicates inserted in the database (which means if the tool is launched twice in a row, no new lines will be inserted)
|
||||
- Tell the user how many new lines are going to be inserted in the database, and ask his agreement before proceeding
|
||||
- Performs the insert in the database
|
||||
|
||||
this project is written in Rust.
|
||||
233
Cargo.lock
generated
Normal file
233
Cargo.lock
generated
Normal file
@@ -0,0 +1,233 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "csv"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938"
|
||||
dependencies = [
|
||||
"csv-core",
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "csv-core"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fallible-iterator"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
|
||||
|
||||
[[package]]
|
||||
name = "fallible-streaming-iterator"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashlink"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.30.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149"
|
||||
dependencies = [
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pushWaterCar"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"csv",
|
||||
"rusqlite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusqlite"
|
||||
version = "0.32.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"fallible-iterator",
|
||||
"fallible-streaming-iterator",
|
||||
"hashlink",
|
||||
"libsqlite3-sys",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984"
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.114"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.8.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd"
|
||||
dependencies = [
|
||||
"zerocopy-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy-derive"
|
||||
version = "0.8.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
@@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "pushWaterCar"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
csv = "1.3"
|
||||
rusqlite = "0.32"
|
||||
52
data/manual.csv
Normal file
52
data/manual.csv
Normal file
@@ -0,0 +1,52 @@
|
||||
Date;Eau;Scénic;Zoé
|
||||
5/1/24;38,76;94990;50621
|
||||
13/1/24;41,64;95497;50850
|
||||
27/1/24;47,18;95829;51491
|
||||
3/2/24;48,28;95892;51741
|
||||
17/2/24;53,99;96107;52503
|
||||
25/2/24;57,60;96190;52744
|
||||
2/3/24;60,96;96309;52963
|
||||
23/3/24;68,78;97289;
|
||||
31/3/24;71,70;97398;54293
|
||||
20/04/24;78,04;98083;54992
|
||||
27/4/24;80,76;98315;55244
|
||||
16/11/24;151,21;105935;63316
|
||||
24/11/24;154,54;106166;63806
|
||||
7/12/24;159,68;106562;64605
|
||||
15/12/24;162,13;106689;65055
|
||||
21/12/24;165,41;106806;65453
|
||||
28/12/24;168,26;107174;65575
|
||||
4/1/25;170,91;107174;65883
|
||||
11/1/25;173,21;107308;66139
|
||||
18/1/25;175,67;107460;66568
|
||||
1/2/25;181,12;107744;67165
|
||||
9/2/25;183,66;108148;67558
|
||||
15/2/25;185,88;108375;67845
|
||||
23/2/25;189,43;108560;68285
|
||||
2/3/25;192,10;108722;68667
|
||||
8/3/25;193,80;108833;69005
|
||||
15/3/25;196,24;109111;69395
|
||||
29/3/25;200,46;109639;69858
|
||||
6/4/25;203,63;109883;70116
|
||||
12/4/25;204,95;110217;70379
|
||||
22/4/25;207,65;110484;70500
|
||||
3/5/25;210,57;110721;70683
|
||||
18/5/25;215,81;110926;70950
|
||||
23/5/25;217,53;111019;71080
|
||||
7/6/25;221,89;111542;71403
|
||||
28/6/25;227,96;111822;71725
|
||||
24/7/25;234,95;112108;72330
|
||||
9/8/25;239,54;112329;72539
|
||||
24/8/25;242,01;113194;72603
|
||||
13/9/25;247,96;113340;73232
|
||||
21/9/25;250,43;113434;73478
|
||||
28/9/25;252,17;113528;73582
|
||||
4/10/25;254,48;113626;73735
|
||||
11/10/25;256,47;113745;73800
|
||||
19/10/25;259,36;113845;74020
|
||||
2/11/25;264,26;114238;74279
|
||||
12/11/25;267,02;114238;74567
|
||||
23/11/25;270,80;114780;74880
|
||||
29/11/25;272,64;114643;74905
|
||||
7/12/25;275,31;114812;75091
|
||||
23/12/25;280,52;115327;75602
|
||||
|
233
src/main.rs
Normal file
233
src/main.rs
Normal file
@@ -0,0 +1,233 @@
|
||||
use csv::ReaderBuilder;
|
||||
use rusqlite::Connection;
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::{self, BufRead, Write};
|
||||
use std::path::Path;
|
||||
use std::process;
|
||||
|
||||
const EXPECTED_HEADERS: [&str; 4] = ["Date", "Eau", "Scénic", "Zoé"];
|
||||
|
||||
fn main() {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
|
||||
if args.len() != 3 {
|
||||
eprintln!("Usage: {} <csv_file> <jdbc_url>", args[0]);
|
||||
eprintln!("Example: {} data/manual.csv jdbc:sqlite:/path/to/conso.db", args[0]);
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
let csv_path = &args[1];
|
||||
let jdbc_url = &args[2];
|
||||
|
||||
// Parse JDBC URL to get SQLite path
|
||||
let db_path = match parse_jdbc_url(jdbc_url) {
|
||||
Some(path) => path,
|
||||
None => {
|
||||
eprintln!("Error: Invalid JDBC URL. Expected format: jdbc:sqlite:/path/to/database.db");
|
||||
process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
// Validate CSV file exists
|
||||
if !Path::new(csv_path).exists() {
|
||||
eprintln!("Error: CSV file not found: {}", csv_path);
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
// Validate database file exists
|
||||
if !Path::new(&db_path).exists() {
|
||||
eprintln!("Error: Database file not found: {}", db_path);
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
// Open database connection
|
||||
let conn = match Connection::open(&db_path) {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
eprintln!("Error: Cannot connect to database: {}", e);
|
||||
process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
// Read and validate CSV
|
||||
let records = match read_csv(csv_path) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
eprintln!("Error reading CSV: {}", e);
|
||||
process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
// Get existing dates from each table
|
||||
let existing_eau = get_existing_dates(&conn, "eau");
|
||||
let existing_voiture1 = get_existing_dates(&conn, "voiture1");
|
||||
let existing_voiture2 = get_existing_dates(&conn, "voiture2");
|
||||
|
||||
// Filter records to find new ones for each table
|
||||
let mut new_eau: Vec<(&str, f64)> = Vec::new();
|
||||
let mut new_voiture1: Vec<(&str, i64)> = Vec::new();
|
||||
let mut new_voiture2: Vec<(&str, i64)> = Vec::new();
|
||||
|
||||
for record in &records {
|
||||
if !existing_eau.contains(&record.date) {
|
||||
if let Some(val) = record.eau {
|
||||
new_eau.push((&record.date, val));
|
||||
}
|
||||
}
|
||||
if !existing_voiture1.contains(&record.date) {
|
||||
if let Some(val) = record.scenic {
|
||||
new_voiture1.push((&record.date, val));
|
||||
}
|
||||
}
|
||||
if !existing_voiture2.contains(&record.date) {
|
||||
if let Some(val) = record.zoe {
|
||||
new_voiture2.push((&record.date, val));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Show summary
|
||||
println!("New rows to insert:");
|
||||
println!(" - eau: {} rows", new_eau.len());
|
||||
println!(" - voiture1: {} rows", new_voiture1.len());
|
||||
println!(" - voiture2: {} rows", new_voiture2.len());
|
||||
|
||||
let total = new_eau.len() + new_voiture1.len() + new_voiture2.len();
|
||||
if total == 0 {
|
||||
println!("\nNo new data to insert. Database is up to date.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Ask for confirmation
|
||||
print!("\nProceed with insertion? (y/N): ");
|
||||
io::stdout().flush().unwrap();
|
||||
|
||||
let mut input = String::new();
|
||||
io::stdin().lock().read_line(&mut input).unwrap();
|
||||
|
||||
if input.trim().to_lowercase() != "y" {
|
||||
println!("Aborted.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform insertions
|
||||
if let Err(e) = insert_data(&conn, &new_eau, &new_voiture1, &new_voiture2) {
|
||||
eprintln!("Error during insertion: {}", e);
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
println!("Done! Inserted {} rows total.", total);
|
||||
}
|
||||
|
||||
fn parse_jdbc_url(url: &str) -> Option<String> {
|
||||
url.strip_prefix("jdbc:sqlite:").map(|s| s.to_string())
|
||||
}
|
||||
|
||||
struct Record {
|
||||
date: String,
|
||||
eau: Option<f64>,
|
||||
scenic: Option<i64>,
|
||||
zoe: Option<i64>,
|
||||
}
|
||||
|
||||
fn read_csv(path: &str) -> Result<Vec<Record>, String> {
|
||||
let file = File::open(path).map_err(|e| format!("Cannot open file: {}", e))?;
|
||||
|
||||
let mut reader = ReaderBuilder::new()
|
||||
.delimiter(b';')
|
||||
.from_reader(file);
|
||||
|
||||
// Validate headers
|
||||
let headers = reader.headers().map_err(|e| format!("Cannot read headers: {}", e))?;
|
||||
let header_vec: Vec<&str> = headers.iter().collect();
|
||||
|
||||
if header_vec != EXPECTED_HEADERS {
|
||||
return Err(format!(
|
||||
"Invalid CSV headers. Expected {:?}, got {:?}",
|
||||
EXPECTED_HEADERS, header_vec
|
||||
));
|
||||
}
|
||||
|
||||
let mut records = Vec::new();
|
||||
|
||||
for (line_num, result) in reader.records().enumerate() {
|
||||
let record = result.map_err(|e| format!("Error reading line {}: {}", line_num + 2, e))?;
|
||||
|
||||
let date = record.get(0).unwrap_or("").trim().to_string();
|
||||
if date.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let eau = parse_french_decimal(record.get(1).unwrap_or(""));
|
||||
let scenic = parse_integer(record.get(2).unwrap_or(""));
|
||||
let zoe = parse_integer(record.get(3).unwrap_or(""));
|
||||
|
||||
records.push(Record { date, eau, scenic, zoe });
|
||||
}
|
||||
|
||||
Ok(records)
|
||||
}
|
||||
|
||||
fn parse_french_decimal(s: &str) -> Option<f64> {
|
||||
let s = s.trim();
|
||||
if s.is_empty() {
|
||||
return None;
|
||||
}
|
||||
// Replace French decimal comma with dot
|
||||
let normalized = s.replace(',', ".");
|
||||
normalized.parse().ok()
|
||||
}
|
||||
|
||||
fn parse_integer(s: &str) -> Option<i64> {
|
||||
let s = s.trim();
|
||||
if s.is_empty() {
|
||||
return None;
|
||||
}
|
||||
// Handle potential decimal values by parsing as float first and converting
|
||||
let normalized = s.replace(',', ".");
|
||||
normalized.parse::<f64>().ok().map(|f| f as i64)
|
||||
}
|
||||
|
||||
fn get_existing_dates(conn: &Connection, table: &str) -> HashSet<String> {
|
||||
let mut dates = HashSet::new();
|
||||
let query = format!("SELECT date FROM {}", table);
|
||||
|
||||
if let Ok(mut stmt) = conn.prepare(&query) {
|
||||
if let Ok(rows) = stmt.query_map([], |row| row.get::<_, String>(0)) {
|
||||
for date in rows.flatten() {
|
||||
dates.insert(date);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dates
|
||||
}
|
||||
|
||||
fn insert_data(
|
||||
conn: &Connection,
|
||||
eau: &[(&str, f64)],
|
||||
voiture1: &[(&str, i64)],
|
||||
voiture2: &[(&str, i64)],
|
||||
) -> Result<(), rusqlite::Error> {
|
||||
// Insert eau records
|
||||
let mut stmt = conn.prepare("INSERT INTO eau (date, releve) VALUES (?, ?)")?;
|
||||
for (date, releve) in eau {
|
||||
stmt.execute(rusqlite::params![date, releve])?;
|
||||
}
|
||||
|
||||
// Insert voiture1 records
|
||||
let mut stmt = conn.prepare("INSERT INTO voiture1 (date, releve) VALUES (?, ?)")?;
|
||||
for (date, releve) in voiture1 {
|
||||
stmt.execute(rusqlite::params![date, releve])?;
|
||||
}
|
||||
|
||||
// Insert voiture2 records
|
||||
let mut stmt = conn.prepare("INSERT INTO voiture2 (date, releve) VALUES (?, ?)")?;
|
||||
for (date, releve) in voiture2 {
|
||||
stmt.execute(rusqlite::params![date, releve])?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user