add exporting
This commit is contained in:
parent
ec375f14f7
commit
bcd2e9086b
9 changed files with 137 additions and 1 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -2790,6 +2790,10 @@ dependencies = [
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "panorama-macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.12.3"
|
version = "0.12.3"
|
||||||
|
|
1
crates/panorama-daemon/.gitignore
vendored
Normal file
1
crates/panorama-daemon/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export
|
82
crates/panorama-daemon/src/export.rs
Normal file
82
crates/panorama-daemon/src/export.rs
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
fs::{self, File},
|
||||||
|
io::{BufWriter, Write},
|
||||||
|
path::PathBuf,
|
||||||
|
};
|
||||||
|
|
||||||
|
use axum::extract::State;
|
||||||
|
use cozo::ScriptMutability;
|
||||||
|
|
||||||
|
use crate::{error::AppResult, AppState};
|
||||||
|
|
||||||
|
pub async fn export(State(state): State<AppState>) -> AppResult<()> {
|
||||||
|
let result = state.db.run_script(
|
||||||
|
"::relations",
|
||||||
|
Default::default(),
|
||||||
|
ScriptMutability::Immutable,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let name_index = result.headers.iter().position(|x| x == "name").unwrap();
|
||||||
|
let relation_names = result
|
||||||
|
.rows
|
||||||
|
.into_iter()
|
||||||
|
.map(|row| row[name_index].get_str().unwrap().to_owned())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let mut relation_columns = HashMap::new();
|
||||||
|
|
||||||
|
for relation_name in relation_names.iter() {
|
||||||
|
let result = state.db.run_script(
|
||||||
|
&format!("::columns {relation_name}"),
|
||||||
|
Default::default(),
|
||||||
|
ScriptMutability::Immutable,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let column_index =
|
||||||
|
result.headers.iter().position(|x| x == "column").unwrap();
|
||||||
|
let columns = result
|
||||||
|
.rows
|
||||||
|
.into_iter()
|
||||||
|
.map(|row| row[column_index].get_str().unwrap().to_owned())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
relation_columns.insert(relation_name.clone(), columns);
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("columns: {relation_columns:?}");
|
||||||
|
|
||||||
|
let base_dir = PathBuf::from("export");
|
||||||
|
fs::create_dir_all(&base_dir);
|
||||||
|
|
||||||
|
let tx = state.db.multi_transaction(false);
|
||||||
|
|
||||||
|
for relation_name in relation_names.iter() {
|
||||||
|
let relation_path = base_dir.join(format!("{relation_name}.ndjson"));
|
||||||
|
let mut file = File::create(&relation_path).unwrap();
|
||||||
|
|
||||||
|
let columns = relation_columns
|
||||||
|
.get(relation_name.as_str())
|
||||||
|
.unwrap()
|
||||||
|
.join(", ");
|
||||||
|
|
||||||
|
let query = format!("?[{columns}] := *{relation_name} {{ {columns} }}");
|
||||||
|
println!("Query: {query}");
|
||||||
|
let result = tx.run_script(&query, Default::default())?;
|
||||||
|
|
||||||
|
for row in result.rows.into_iter() {
|
||||||
|
let mut object = HashMap::new();
|
||||||
|
|
||||||
|
for (idx, col) in row.into_iter().enumerate() {
|
||||||
|
let row_name = result.headers[idx].clone();
|
||||||
|
object.insert(row_name, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
let serialized = serde_json::to_string(&object).unwrap();
|
||||||
|
file.write(serialized.as_bytes());
|
||||||
|
file.write(b"\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -8,9 +8,11 @@ extern crate serde_json;
|
||||||
extern crate sugars;
|
extern crate sugars;
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
|
mod export;
|
||||||
mod journal;
|
mod journal;
|
||||||
mod migrations;
|
mod migrations;
|
||||||
mod node;
|
mod node;
|
||||||
|
mod query_builder;
|
||||||
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
|
@ -27,6 +29,7 @@ use tower::ServiceBuilder;
|
||||||
use tower_http::cors::{self, CorsLayer};
|
use tower_http::cors::{self, CorsLayer};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
export::export,
|
||||||
journal::get_todays_journal_id,
|
journal::get_todays_journal_id,
|
||||||
migrations::run_migrations,
|
migrations::run_migrations,
|
||||||
node::{get_node, node_types, update_node},
|
node::{get_node, node_types, update_node},
|
||||||
|
@ -64,6 +67,7 @@ async fn main() -> Result<()> {
|
||||||
// build our application with a single route
|
// build our application with a single route
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route("/", get(|| async { "Hello, World!" }))
|
.route("/", get(|| async { "Hello, World!" }))
|
||||||
|
.route("/export", get(export))
|
||||||
.route("/node/:id", get(get_node))
|
.route("/node/:id", get(get_node))
|
||||||
.route("/node/:id", post(update_node))
|
.route("/node/:id", post(update_node))
|
||||||
.route("/node/types", get(node_types))
|
.route("/node/types", get(node_types))
|
||||||
|
|
|
@ -117,6 +117,15 @@ fn migration_01(db: &DbInstance) -> Result<()> {
|
||||||
{ :create node_has_key { key: String => id: String } }
|
{ :create node_has_key { key: String => id: String } }
|
||||||
{ :create node_managed_by_app { node_id: String => app: String } }
|
{ :create node_managed_by_app { node_id: String => app: String } }
|
||||||
{ :create node_refers_to { node_id: String => other_node_id: String } }
|
{ :create node_refers_to { node_id: String => other_node_id: String } }
|
||||||
|
{
|
||||||
|
:create fqkey_to_dbkey {
|
||||||
|
key: String
|
||||||
|
=>
|
||||||
|
relation: String,
|
||||||
|
field_name: String,
|
||||||
|
type: String,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Create journal type
|
# Create journal type
|
||||||
{ :create journal { node_id: String => content: Json } }
|
{ :create journal { node_id: String => content: Json } }
|
||||||
|
|
|
@ -5,7 +5,7 @@ use axum::{
|
||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
Json,
|
Json,
|
||||||
};
|
};
|
||||||
use cozo::ScriptMutability;
|
use cozo::{DataValue, ScriptMutability};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use crate::{error::AppResult, AppState};
|
use crate::{error::AppResult, AppState};
|
||||||
|
@ -70,6 +70,30 @@ pub async fn update_node(
|
||||||
) -> AppResult<Json<Value>> {
|
) -> AppResult<Json<Value>> {
|
||||||
println!("Update data: {:?}", update_data);
|
println!("Update data: {:?}", update_data);
|
||||||
|
|
||||||
|
let tx = state.db.multi_transaction(true);
|
||||||
|
|
||||||
|
if let Some(extra_data) = update_data.extra_data {
|
||||||
|
let result = tx.run_script(
|
||||||
|
"
|
||||||
|
?[relation, field_name, type] :=
|
||||||
|
*fqkey_to_dbkey{key, relation, field_name, type},
|
||||||
|
key = $key
|
||||||
|
",
|
||||||
|
btmap! {
|
||||||
|
"key".to_owned() => DataValue::List(
|
||||||
|
extra_data
|
||||||
|
.keys()
|
||||||
|
.map(|s| DataValue::from(s.as_str()))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
),
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
println!("Result: {result:?}");
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.commit()?;
|
||||||
|
|
||||||
Ok(Json(json!({})))
|
Ok(Json(json!({})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
crates/panorama-daemon/src/query_builder.rs
Normal file
2
crates/panorama-daemon/src/query_builder.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct QueryBuilder {}
|
9
crates/panorama-macros/Cargo.toml
Normal file
9
crates/panorama-macros/Cargo.toml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
[package]
|
||||||
|
name = "panorama-macros"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
proc-macro = true
|
||||||
|
|
||||||
|
[dependencies]
|
1
crates/panorama-macros/src/lib.rs
Normal file
1
crates/panorama-macros/src/lib.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
// TODO: derive named rows
|
Loading…
Reference in a new issue