third pass, compiles and should work

This commit is contained in:
Grisha Kruglov 2018-01-31 22:05:49 -05:00
parent 96ea7dc86f
commit 4f243fbc32
6 changed files with 88 additions and 44 deletions

View file

@ -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
View 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)
}
}
}

View file

@ -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;

View file

@ -14,7 +14,7 @@ use rusqlite;
use uuid::Uuid;
use schema;
use Result;
use errors::Result;
trait HeadTrackable {
fn remote_head(&self) -> Result<Uuid>;

View file

@ -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"#;

View file

@ -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())
}
}