Skip to content
This repository has been archived by the owner on Oct 27, 2023. It is now read-only.

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Zelak312 committed Aug 3, 2022
0 parents commit e471471
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 0 deletions.
21 changes: 21 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Created by https://www.toptal.com/developers/gitignore/api/rust
# Edit at https://www.toptal.com/developers/gitignore?templates=rust

### Rust ###
# Generated by Cargo
# will have compiled files and executables
debug/
target/

# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock

# These are backup files generated by rustfmt
**/*.rs.bk

# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb

# End of https://www.toptal.com/developers/gitignore/api/rust
samples/
50 changes: 50 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug executable 'quick-db-migration-tool'",
"cargo": {
"args": [
"build",
"--bin=quick-db-migration-tool",
"--package=quick-db-migration-tool"
],
"filter": {
"name": "quick-db-migration-tool",
"kind": "bin"
}
},
"args": [],
"cwd": "${workspaceFolder}"
},
{
"type": "lldb",
"request": "launch",
"name": "Debug unit tests in executable 'quick-db-migration-tool'",
"cargo": {
"args": [
"test",
"--no-run",
"--bin=quick-db-migration-tool",
"--package=quick-db-migration-tool"
],
"filter": {
"name": "quick-db-migration-tool",
"kind": "bin"
}
},
"args": [
"--input",
"./samples/json.sqlite",
"--output",
"../test.sqlite"
],
"cwd": "${workspaceFolder}"
}
]
}
11 changes: 11 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "quick-db-migration-tool"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
clap = { version = "3.2.16", features = ["derive"] }
serde_json = "1.0.82"
sqlite = "0.27.0"
98 changes: 98 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
use clap::Parser;
use serde_json::Value;
use sqlite::Connection;
use std::path::Path;

#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
struct Args {
/// Sqlite file to migrate
#[clap(short, long, value_parser)]
input: String,

/// Sqlite output file
#[clap(short, long, value_parser)]
output: String,
}

fn get_tables(connection: &Connection) -> Vec<String> {
let cursor = connection
.prepare("SELECT name FROM sqlite_schema WHERE type = ? AND name NOT LIKE ?")
.unwrap()
.bind(1, "table")
.unwrap()
.bind(2, "sqlite_%")
.unwrap()
.into_cursor();

cursor.map(|row| row.unwrap().get::<String, _>(0)).collect()
}

fn process_table(connection: &Connection, conn_out: &Connection, table: String) {
println!("Processing {} table", table);

conn_out
.execute(format!("CREATE TABLE '{}' (ID TEXT, json TEXT)", table))
.unwrap();

let mut cursor = connection
.prepare(format!("SELECT ID, json FROM '{}'", table))
.unwrap()
.into_cursor();

while let Some(Ok(row)) = cursor.next() {
let id = row.get::<String, _>("ID");
let json = process_row(&id, row.get("json"));
conn_out
.execute(format!(
"INSERT INTO '{}' (ID, json)
VALUES ('{}', '{}'); ",
table, &id, json
))
.unwrap();
}
}

fn process_row(id: &str, json: String) -> String {
println!("Processing row with key {}", id);

// Parsing json until it matches
let tmp_val = serde_json::from_str::<Value>(&json).unwrap();
let mut tmp = tmp_val.as_str().unwrap().to_owned();
loop {
let current_val = serde_json::from_str::<Value>(&tmp).unwrap();
if current_val.as_str().is_none() {
break;
}

tmp = current_val.as_str().unwrap().to_string();
}

tmp
}

fn main() {
let args = Args::parse();
if args.input == args.output {
panic!("Can't have the same output for input");
}

println!("Loading {} sqlite file", args.input);

let connection = sqlite::open(args.input).expect("Couldn't find input sqlite file");
println!("Sqlite loaded");
println!("Creating output sqlite file");
if Path::new(&args.output).exists() {
panic!("Output file already exist");
}

let conn_output = sqlite::open(args.output).expect("Couldn't create output sqlite file");
println!("Getting tables");

let tables = get_tables(&connection);
println!("Found tables {:?}", tables);

for table in tables {
process_table(&connection, &conn_output, table);
}
}

0 comments on commit e471471

Please sign in to comment.