third pass, compiles and should work
This commit is contained in:
parent
96ea7dc86f
commit
4f243fbc32
6 changed files with 88 additions and 44 deletions
|
@ -37,7 +37,7 @@ pub mod db;
|
|||
mod bootstrap;
|
||||
pub mod debug;
|
||||
mod add_retract_alter_set;
|
||||
mod entids;
|
||||
pub mod entids;
|
||||
pub mod errors;
|
||||
mod metadata;
|
||||
mod schema;
|
||||
|
|
41
tolstoy/src/errors.rs
Normal file
41
tolstoy/src/errors.rs
Normal file
|
@ -0,0 +1,41 @@
|
|||
// Copyright 2016 Mozilla
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
// this file except in compliance with the License. You may obtain a copy of the
|
||||
// License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
// Unless required by applicable law or agreed to in writing, software distributed
|
||||
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std;
|
||||
use hyper;
|
||||
use rusqlite;
|
||||
use edn;
|
||||
use mentat_db;
|
||||
|
||||
error_chain! {
|
||||
types {
|
||||
Error, ErrorKind, ResultExt, Result;
|
||||
}
|
||||
|
||||
foreign_links {
|
||||
IOError(std::io::Error);
|
||||
HttpError(hyper::Error);
|
||||
SqlError(rusqlite::Error);
|
||||
UuidParseError(edn::UuidParseError);
|
||||
}
|
||||
|
||||
links {
|
||||
DbError(mentat_db::Error, mentat_db::ErrorKind);
|
||||
}
|
||||
|
||||
errors {
|
||||
UnexpectedState(t: String) {
|
||||
description("encountered unexpected state")
|
||||
display("encountered unexpected state: {}", t)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,16 +28,4 @@ extern crate uuid;
|
|||
pub mod schema;
|
||||
pub mod metadata;
|
||||
pub mod tx_client;
|
||||
|
||||
error_chain! {
|
||||
types {
|
||||
Error, ErrorKind, ResultExt, Result;
|
||||
}
|
||||
|
||||
foreign_links {
|
||||
IOError(std::io::Error);
|
||||
HttpError(hyper::Error);
|
||||
SqlError(rusqlite::Error);
|
||||
UuidParseError(edn::UuidParseError);
|
||||
}
|
||||
}
|
||||
pub mod errors;
|
||||
|
|
|
@ -14,7 +14,7 @@ use rusqlite;
|
|||
use uuid::Uuid;
|
||||
|
||||
use schema;
|
||||
use Result;
|
||||
use errors::Result;
|
||||
|
||||
trait HeadTrackable {
|
||||
fn remote_head(&self) -> Result<Uuid>;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// specific language governing permissions and limitations under the License.
|
||||
|
||||
use rusqlite;
|
||||
use Result;
|
||||
use errors::Result;
|
||||
|
||||
pub static REMOTE_HEAD_KEY: &str = r#"remote_head"#;
|
||||
|
||||
|
|
|
@ -25,29 +25,36 @@
|
|||
// perhaps mentat has useful primitives, but let's begin by just "doing the work"
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::hash_map::Entry;
|
||||
|
||||
use rusqlite;
|
||||
|
||||
use Result;
|
||||
use errors::{
|
||||
Result
|
||||
};
|
||||
|
||||
use mentat_db::types::{
|
||||
Entid
|
||||
};
|
||||
|
||||
use mentat_db::{
|
||||
entids,
|
||||
TypedSQLValue
|
||||
};
|
||||
|
||||
use mentat_core::{
|
||||
DateTime,
|
||||
Utc,
|
||||
ValueType
|
||||
TypedValue
|
||||
};
|
||||
|
||||
use mentat_core::SQLValueType;
|
||||
use edn::FromMicros;
|
||||
|
||||
pub struct TxPart {
|
||||
e: Entid,
|
||||
a: i32,
|
||||
v: Vec<u8>, // should be TypedValue to allow for variety of types
|
||||
added: i32,
|
||||
value_type_tag: i32 // with v as TypedValue, shouldn't be necessary
|
||||
a: i64,
|
||||
v: TypedValue,
|
||||
added: i32
|
||||
}
|
||||
|
||||
pub struct Tx {
|
||||
|
@ -77,50 +84,58 @@ impl TxClient {
|
|||
impl TxReader for TxClient {
|
||||
fn txs(&self) -> Result<Vec<Tx>> {
|
||||
let mut txes_by_tx = HashMap::new();
|
||||
let mut parts_keyed_by_tx = HashMap::new();
|
||||
|
||||
let mut stmt = self.conn.prepare("SELECT e, a, v, tx, added, value_type_tag, CASE a WHEN :txInstant THEN 1 ELSE 0 END is_transaction FROM transactions ORDER BY is_transaction DESC")?;
|
||||
let mapped_rows = stmt.query_map_named(&[(":txInstant", entids::DB_TX_INSTANT)], |row| {
|
||||
// Make sure a=txInstant rows are first, so that we process
|
||||
// all transactions before we process any transaction parts.
|
||||
let mut stmt = self.conn.prepare(
|
||||
"SELECT
|
||||
e, a, v, tx, added, value_type_tag,
|
||||
CASE a WHEN :txInstant THEN 1 ELSE 0 END is_transaction
|
||||
FROM transactions ORDER BY is_transaction DESC"
|
||||
)?;
|
||||
let _ = stmt.query_and_then_named(&[(":txInstant", &entids::DB_TX_INSTANT)], |row| {
|
||||
let e = row.get(0);
|
||||
let a = row.get(1);
|
||||
let v = row.get(2);
|
||||
let v_instant: i64 = row.get(2); // TODO unify this and typed_value below
|
||||
let tx = row.get(3);
|
||||
let added = row.get(4);
|
||||
let value_type_tag = row.get(5);
|
||||
|
||||
|
||||
let raw_value: rusqlite::types::Value = row.get(2);
|
||||
let typed_value = match TypedValue::from_sql_value_pair(raw_value, value_type_tag) {
|
||||
Ok(v) => v,
|
||||
Err(e) => return Err(e)
|
||||
};
|
||||
|
||||
// Row represents a transaction.
|
||||
if a == entids::DB_TX_INSTANT {
|
||||
txes_by_tx.insert(tx, Tx {
|
||||
tx: tx,
|
||||
tx_instant: DateTime::<Utc>::from_micros(v),
|
||||
// TODO enforce correct type of v and return ErrorKind::BadSQLValuePair
|
||||
// otherwise.
|
||||
tx_instant: DateTime::<Utc>::from_micros(v_instant),
|
||||
parts: Vec::new()
|
||||
});
|
||||
Ok(())
|
||||
// Row represents part of a transaction. Our query statement above guarantees
|
||||
// that we've already processed corresponding transaction at this point.
|
||||
} else {
|
||||
if let Entry::Occupied(o) = txes_by_tx.entry(tx) {
|
||||
*o.get_mut().parts.push(TxPart {
|
||||
if let Entry::Occupied(mut t) = txes_by_tx.entry(tx) {
|
||||
t.get_mut().parts.push(TxPart {
|
||||
e: e,
|
||||
a: a,
|
||||
v: v, // TODO tx_instant conversion implied that this value is i64... but it can be many things
|
||||
added: added,
|
||||
value_type_tag: value_type_tag
|
||||
v: typed_value,
|
||||
added: added
|
||||
});
|
||||
Ok(())
|
||||
} else {
|
||||
// Shouldn't happen if our query is correct.
|
||||
// TODO not ok... ErrorKind::UnexpectedError
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
})?;
|
||||
|
||||
let mut txes = Vec::new();
|
||||
for tx in mapped_rows {
|
||||
txes.push(match tx? {
|
||||
Err(e) => return Err(e),
|
||||
Ok(v) => v
|
||||
});
|
||||
}
|
||||
|
||||
Ok(txes)
|
||||
Ok(txes_by_tx.into_iter().map(|(_, tx)| tx).collect())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue