Part 1: parse #inst in EDN and throughout query engine.
This commit is contained in:
parent
f21a285afb
commit
2b53abbd85
9 changed files with 153 additions and 14 deletions
|
@ -33,6 +33,13 @@ pub use edn::{
|
||||||
Uuid,
|
Uuid,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub use edn::{
|
||||||
|
DateTime,
|
||||||
|
FromMicros,
|
||||||
|
ToMicros,
|
||||||
|
UTC,
|
||||||
|
};
|
||||||
|
|
||||||
/// Core types defining a Mentat knowledge base.
|
/// Core types defining a Mentat knowledge base.
|
||||||
|
|
||||||
/// Represents one entid in the entid space.
|
/// Represents one entid in the entid space.
|
||||||
|
@ -123,6 +130,7 @@ pub enum TypedValue {
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
Long(i64),
|
Long(i64),
|
||||||
Double(OrderedFloat<f64>),
|
Double(OrderedFloat<f64>),
|
||||||
|
Instant(DateTime<UTC>),
|
||||||
// TODO: &str throughout?
|
// TODO: &str throughout?
|
||||||
String(Rc<String>),
|
String(Rc<String>),
|
||||||
Keyword(Rc<NamespacedKeyword>),
|
Keyword(Rc<NamespacedKeyword>),
|
||||||
|
@ -147,6 +155,7 @@ impl TypedValue {
|
||||||
&TypedValue::Ref(_) => ValueType::Ref,
|
&TypedValue::Ref(_) => ValueType::Ref,
|
||||||
&TypedValue::Boolean(_) => ValueType::Boolean,
|
&TypedValue::Boolean(_) => ValueType::Boolean,
|
||||||
&TypedValue::Long(_) => ValueType::Long,
|
&TypedValue::Long(_) => ValueType::Long,
|
||||||
|
&TypedValue::Instant(_) => ValueType::Instant,
|
||||||
&TypedValue::Double(_) => ValueType::Double,
|
&TypedValue::Double(_) => ValueType::Double,
|
||||||
&TypedValue::String(_) => ValueType::String,
|
&TypedValue::String(_) => ValueType::String,
|
||||||
&TypedValue::Keyword(_) => ValueType::Keyword,
|
&TypedValue::Keyword(_) => ValueType::Keyword,
|
||||||
|
@ -167,6 +176,10 @@ impl TypedValue {
|
||||||
pub fn typed_string(s: &str) -> TypedValue {
|
pub fn typed_string(s: &str) -> TypedValue {
|
||||||
TypedValue::String(Rc::new(s.to_string()))
|
TypedValue::String(Rc::new(s.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn current_instant() -> TypedValue {
|
||||||
|
TypedValue::Instant(UTC::now())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put this here rather than in `db` simply because it's widely needed.
|
// Put this here rather than in `db` simply because it's widely needed.
|
||||||
|
|
|
@ -11,6 +11,7 @@ build = "build.rs"
|
||||||
readme = "./README.md"
|
readme = "./README.md"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
chrono = "0.3"
|
||||||
itertools = "0.5.9"
|
itertools = "0.5.9"
|
||||||
num = "0.1.35"
|
num = "0.1.35"
|
||||||
ordered-float = "0.4.0"
|
ordered-float = "0.4.0"
|
||||||
|
|
|
@ -14,6 +14,11 @@ use std::collections::{BTreeSet, BTreeMap, LinkedList};
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
use std::f64::{NAN, INFINITY, NEG_INFINITY};
|
use std::f64::{NAN, INFINITY, NEG_INFINITY};
|
||||||
|
|
||||||
|
use chrono::{
|
||||||
|
DateTime,
|
||||||
|
TimeZone,
|
||||||
|
UTC
|
||||||
|
};
|
||||||
use num::BigInt;
|
use num::BigInt;
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
@ -143,6 +148,39 @@ pub text -> ValueAndSpan =
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// RFC 3339 timestamps. #inst "1985-04-12T23:20:50.52Z"
|
||||||
|
// We accept an arbitrary depth of decimals.
|
||||||
|
// Note that we discard the timezone information -- all times are translated to UTC.
|
||||||
|
pub inst_string -> DateTime<UTC> =
|
||||||
|
"\"" d:$( [0-9]*<4> "-" [0-2][0-9] "-" [0-3][0-9]
|
||||||
|
"T"
|
||||||
|
[0-2][0-9] ":" [0-5][0-9] ":" [0-6][0-9]
|
||||||
|
("." [0-9]+)?
|
||||||
|
"Z" / (("+" / "-") [0-2][0-9] ":" [0-5][0-9])
|
||||||
|
)
|
||||||
|
"\"" {?
|
||||||
|
DateTime::parse_from_rfc3339(d)
|
||||||
|
.map(|t| t.with_timezone(&UTC))
|
||||||
|
.map_err(|_| "invalid datetime") // Oh, rustpeg.
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inst_millis -> DateTime<UTC> =
|
||||||
|
d:$( digit+ ) {
|
||||||
|
let millis = d.parse::<i64>().unwrap();
|
||||||
|
let seconds: i64 = millis / 1000;
|
||||||
|
let nanos: u32 = ((millis % 1000).abs() as u32) * 1000000;
|
||||||
|
UTC.timestamp(seconds, nanos)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inst -> ValueAndSpan =
|
||||||
|
start:#position "#inst" whitespace+ t:(inst_millis / inst_string) end:#position {
|
||||||
|
ValueAndSpan {
|
||||||
|
inner: SpannedValue::Instant(t),
|
||||||
|
span: Span::new(start, end)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub uuid_string -> Uuid =
|
pub uuid_string -> Uuid =
|
||||||
"\"" u:$( [a-f0-9]*<8> "-" [a-f0-9]*<4> "-" [a-f0-9]*<4> "-" [a-f0-9]*<4> "-" [a-f0-9]*<12> ) "\"" {
|
"\"" u:$( [a-f0-9]*<8> "-" [a-f0-9]*<4> "-" [a-f0-9]*<4> "-" [a-f0-9]*<4> "-" [a-f0-9]*<12> ) "\"" {
|
||||||
Uuid::parse_str(u).expect("this is a valid UUID string")
|
Uuid::parse_str(u).expect("this is a valid UUID string")
|
||||||
|
@ -234,7 +272,7 @@ pub map -> ValueAndSpan =
|
||||||
// It's important that float comes before integer or the parser assumes that
|
// It's important that float comes before integer or the parser assumes that
|
||||||
// floats are integers and fails to parse
|
// floats are integers and fails to parse
|
||||||
pub value -> ValueAndSpan =
|
pub value -> ValueAndSpan =
|
||||||
__ v:(nil / nan / infinity / boolean / float / octalinteger / hexinteger / basedinteger / uuid / bigint / integer / text / keyword / symbol / list / vector / map / set) __ {
|
__ v:(nil / nan / infinity / boolean / float / octalinteger / hexinteger / basedinteger / inst / uuid / bigint / integer / text / keyword / symbol / list / vector / map / set) __ {
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
// specific language governing permissions and limitations under the License.
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
extern crate chrono;
|
||||||
extern crate itertools;
|
extern crate itertools;
|
||||||
extern crate num;
|
extern crate num;
|
||||||
extern crate ordered_float;
|
extern crate ordered_float;
|
||||||
|
@ -25,11 +26,19 @@ pub mod parse {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-export the types we use.
|
// Re-export the types we use.
|
||||||
|
pub use chrono::{DateTime, UTC};
|
||||||
pub use num::BigInt;
|
pub use num::BigInt;
|
||||||
pub use ordered_float::OrderedFloat;
|
pub use ordered_float::OrderedFloat;
|
||||||
pub use uuid::Uuid;
|
pub use uuid::Uuid;
|
||||||
|
|
||||||
// Export from our modules.
|
// Export from our modules.
|
||||||
pub use parse::ParseError;
|
pub use parse::ParseError;
|
||||||
pub use types::{Span, SpannedValue, Value, ValueAndSpan};
|
pub use types::{
|
||||||
|
FromMicros,
|
||||||
|
Span,
|
||||||
|
SpannedValue,
|
||||||
|
ToMicros,
|
||||||
|
Value,
|
||||||
|
ValueAndSpan,
|
||||||
|
};
|
||||||
pub use symbols::{Keyword, NamespacedKeyword, PlainSymbol, NamespacedSymbol};
|
pub use symbols::{Keyword, NamespacedKeyword, PlainSymbol, NamespacedSymbol};
|
||||||
|
|
|
@ -15,6 +15,11 @@ use std::cmp::{Ordering, Ord, PartialOrd};
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::f64;
|
use std::f64;
|
||||||
|
|
||||||
|
use chrono::{
|
||||||
|
DateTime,
|
||||||
|
TimeZone, // For UTC::timestamp. The compiler incorrectly complains that this is unused.
|
||||||
|
UTC,
|
||||||
|
};
|
||||||
use num::BigInt;
|
use num::BigInt;
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
@ -27,6 +32,7 @@ pub enum Value {
|
||||||
Nil,
|
Nil,
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
Integer(i64),
|
Integer(i64),
|
||||||
|
Instant(DateTime<UTC>),
|
||||||
BigInteger(BigInt),
|
BigInteger(BigInt),
|
||||||
Float(OrderedFloat<f64>),
|
Float(OrderedFloat<f64>),
|
||||||
Text(String),
|
Text(String),
|
||||||
|
@ -55,6 +61,7 @@ pub enum SpannedValue {
|
||||||
Nil,
|
Nil,
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
Integer(i64),
|
Integer(i64),
|
||||||
|
Instant(DateTime<UTC>),
|
||||||
BigInteger(BigInt),
|
BigInteger(BigInt),
|
||||||
Float(OrderedFloat<f64>),
|
Float(OrderedFloat<f64>),
|
||||||
Text(String),
|
Text(String),
|
||||||
|
@ -127,6 +134,7 @@ impl From<SpannedValue> for Value {
|
||||||
SpannedValue::Nil => Value::Nil,
|
SpannedValue::Nil => Value::Nil,
|
||||||
SpannedValue::Boolean(v) => Value::Boolean(v),
|
SpannedValue::Boolean(v) => Value::Boolean(v),
|
||||||
SpannedValue::Integer(v) => Value::Integer(v),
|
SpannedValue::Integer(v) => Value::Integer(v),
|
||||||
|
SpannedValue::Instant(v) => Value::Instant(v),
|
||||||
SpannedValue::BigInteger(v) => Value::BigInteger(v),
|
SpannedValue::BigInteger(v) => Value::BigInteger(v),
|
||||||
SpannedValue::Float(v) => Value::Float(v),
|
SpannedValue::Float(v) => Value::Float(v),
|
||||||
SpannedValue::Text(v) => Value::Text(v),
|
SpannedValue::Text(v) => Value::Text(v),
|
||||||
|
@ -273,6 +281,7 @@ macro_rules! def_common_value_methods {
|
||||||
def_is!(is_nil, $t::Nil);
|
def_is!(is_nil, $t::Nil);
|
||||||
def_is!(is_boolean, $t::Boolean(_));
|
def_is!(is_boolean, $t::Boolean(_));
|
||||||
def_is!(is_integer, $t::Integer(_));
|
def_is!(is_integer, $t::Integer(_));
|
||||||
|
def_is!(is_instant, $t::Instant(_));
|
||||||
def_is!(is_big_integer, $t::BigInteger(_));
|
def_is!(is_big_integer, $t::BigInteger(_));
|
||||||
def_is!(is_float, $t::Float(_));
|
def_is!(is_float, $t::Float(_));
|
||||||
def_is!(is_text, $t::Text(_));
|
def_is!(is_text, $t::Text(_));
|
||||||
|
@ -294,6 +303,7 @@ macro_rules! def_common_value_methods {
|
||||||
|
|
||||||
def_as!(as_boolean, $t::Boolean, bool,);
|
def_as!(as_boolean, $t::Boolean, bool,);
|
||||||
def_as!(as_integer, $t::Integer, i64,);
|
def_as!(as_integer, $t::Integer, i64,);
|
||||||
|
def_as!(as_instant, $t::Instant, DateTime<UTC>,);
|
||||||
def_as!(as_float, $t::Float, f64, |v: OrderedFloat<f64>| v.into_inner());
|
def_as!(as_float, $t::Float, f64, |v: OrderedFloat<f64>| v.into_inner());
|
||||||
|
|
||||||
def_as_ref!(as_big_integer, $t::BigInteger, BigInt);
|
def_as_ref!(as_big_integer, $t::BigInteger, BigInt);
|
||||||
|
@ -311,6 +321,7 @@ macro_rules! def_common_value_methods {
|
||||||
|
|
||||||
def_into!(into_boolean, $t::Boolean, bool,);
|
def_into!(into_boolean, $t::Boolean, bool,);
|
||||||
def_into!(into_integer, $t::Integer, i64,);
|
def_into!(into_integer, $t::Integer, i64,);
|
||||||
|
def_into!(into_instant, $t::Instant, DateTime<UTC>,);
|
||||||
def_into!(into_big_integer, $t::BigInteger, BigInt,);
|
def_into!(into_big_integer, $t::BigInteger, BigInt,);
|
||||||
def_into!(into_ordered_float, $t::Float, OrderedFloat<f64>,);
|
def_into!(into_ordered_float, $t::Float, OrderedFloat<f64>,);
|
||||||
def_into!(into_float, $t::Float, f64, |v: OrderedFloat<f64>| v.into_inner());
|
def_into!(into_float, $t::Float, f64, |v: OrderedFloat<f64>| v.into_inner());
|
||||||
|
@ -344,16 +355,17 @@ macro_rules! def_common_value_methods {
|
||||||
$t::Integer(_) => 2,
|
$t::Integer(_) => 2,
|
||||||
$t::BigInteger(_) => 3,
|
$t::BigInteger(_) => 3,
|
||||||
$t::Float(_) => 4,
|
$t::Float(_) => 4,
|
||||||
$t::Text(_) => 5,
|
$t::Instant(_) => 5,
|
||||||
$t::Uuid(_) => 6,
|
$t::Text(_) => 6,
|
||||||
$t::PlainSymbol(_) => 7,
|
$t::Uuid(_) => 7,
|
||||||
$t::NamespacedSymbol(_) => 8,
|
$t::PlainSymbol(_) => 8,
|
||||||
$t::Keyword(_) => 9,
|
$t::NamespacedSymbol(_) => 9,
|
||||||
$t::NamespacedKeyword(_) => 10,
|
$t::Keyword(_) => 10,
|
||||||
$t::Vector(_) => 11,
|
$t::NamespacedKeyword(_) => 11,
|
||||||
$t::List(_) => 12,
|
$t::Vector(_) => 12,
|
||||||
$t::Set(_) => 13,
|
$t::List(_) => 13,
|
||||||
$t::Map(_) => 14,
|
$t::Set(_) => 14,
|
||||||
|
$t::Map(_) => 15,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,6 +374,7 @@ macro_rules! def_common_value_methods {
|
||||||
$t::Nil => false,
|
$t::Nil => false,
|
||||||
$t::Boolean(_) => false,
|
$t::Boolean(_) => false,
|
||||||
$t::Integer(_) => false,
|
$t::Integer(_) => false,
|
||||||
|
$t::Instant(_) => false,
|
||||||
$t::BigInteger(_) => false,
|
$t::BigInteger(_) => false,
|
||||||
$t::Float(_) => false,
|
$t::Float(_) => false,
|
||||||
$t::Text(_) => false,
|
$t::Text(_) => false,
|
||||||
|
@ -399,6 +412,7 @@ macro_rules! def_common_value_ord {
|
||||||
(&$t::Nil, &$t::Nil) => Ordering::Equal,
|
(&$t::Nil, &$t::Nil) => Ordering::Equal,
|
||||||
(&$t::Boolean(a), &$t::Boolean(b)) => b.cmp(&a),
|
(&$t::Boolean(a), &$t::Boolean(b)) => b.cmp(&a),
|
||||||
(&$t::Integer(a), &$t::Integer(b)) => b.cmp(&a),
|
(&$t::Integer(a), &$t::Integer(b)) => b.cmp(&a),
|
||||||
|
(&$t::Instant(a), &$t::Instant(b)) => b.cmp(&a),
|
||||||
(&$t::BigInteger(ref a), &$t::BigInteger(ref b)) => b.cmp(a),
|
(&$t::BigInteger(ref a), &$t::BigInteger(ref b)) => b.cmp(a),
|
||||||
(&$t::Float(ref a), &$t::Float(ref b)) => b.cmp(a),
|
(&$t::Float(ref a), &$t::Float(ref b)) => b.cmp(a),
|
||||||
(&$t::Text(ref a), &$t::Text(ref b)) => b.cmp(a),
|
(&$t::Text(ref a), &$t::Text(ref b)) => b.cmp(a),
|
||||||
|
@ -425,6 +439,7 @@ macro_rules! def_common_value_display {
|
||||||
$t::Nil => write!($f, "nil"),
|
$t::Nil => write!($f, "nil"),
|
||||||
$t::Boolean(v) => write!($f, "{}", v),
|
$t::Boolean(v) => write!($f, "{}", v),
|
||||||
$t::Integer(v) => write!($f, "{}", v),
|
$t::Integer(v) => write!($f, "{}", v),
|
||||||
|
$t::Instant(v) => write!($f, "{}", v),
|
||||||
$t::BigInteger(ref v) => write!($f, "{}N", v),
|
$t::BigInteger(ref v) => write!($f, "{}N", v),
|
||||||
// TODO: make sure float syntax is correct.
|
// TODO: make sure float syntax is correct.
|
||||||
$t::Float(ref v) => {
|
$t::Float(ref v) => {
|
||||||
|
@ -530,8 +545,29 @@ impl Display for ValueAndSpan {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait FromMicros {
|
||||||
|
fn from_micros(ts: i64) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromMicros for DateTime<UTC> {
|
||||||
|
fn from_micros(ts: i64) -> Self {
|
||||||
|
UTC.timestamp(ts / 100_000, ((ts % 100_000).abs() as u32) * 1_000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ToMicros {
|
||||||
|
fn to_micros(&self) -> i64;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToMicros for DateTime<UTC> {
|
||||||
|
fn to_micros(&self) -> i64 {
|
||||||
|
(self.timestamp() * 100_000) + (self.timestamp_subsec_micros() as i64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
extern crate chrono;
|
||||||
extern crate ordered_float;
|
extern crate ordered_float;
|
||||||
extern crate num;
|
extern crate num;
|
||||||
|
|
||||||
|
@ -544,9 +580,21 @@ mod test {
|
||||||
|
|
||||||
use parse;
|
use parse;
|
||||||
|
|
||||||
|
use chrono::{
|
||||||
|
DateTime,
|
||||||
|
TimeZone,
|
||||||
|
UTC,
|
||||||
|
};
|
||||||
use num::BigInt;
|
use num::BigInt;
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_micros_roundtrip() {
|
||||||
|
let ts_micros: i64 = 1493399581314000;
|
||||||
|
let dt = DateTime::<UTC>::from_micros(ts_micros);
|
||||||
|
assert_eq!(dt.to_micros(), ts_micros);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_value_from() {
|
fn test_value_from() {
|
||||||
assert_eq!(Value::from_float(42f64), Value::Float(OrderedFloat::from(42f64)));
|
assert_eq!(Value::from_float(42f64), Value::Float(OrderedFloat::from(42f64)));
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
// specific language governing permissions and limitations under the License.
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
extern crate chrono;
|
||||||
extern crate edn;
|
extern crate edn;
|
||||||
extern crate num;
|
extern crate num;
|
||||||
extern crate ordered_float;
|
extern crate ordered_float;
|
||||||
|
@ -22,7 +23,17 @@ use num::traits::{Zero, One};
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
|
|
||||||
use edn::parse::{self, ParseError};
|
use edn::parse::{self, ParseError};
|
||||||
use edn::types::{Value, SpannedValue, Span, ValueAndSpan};
|
use edn::types::{
|
||||||
|
Value,
|
||||||
|
ValueAndSpan,
|
||||||
|
Span,
|
||||||
|
SpannedValue,
|
||||||
|
};
|
||||||
|
use uuid::Uuid;
|
||||||
|
use chrono::{
|
||||||
|
TimeZone,
|
||||||
|
UTC,
|
||||||
|
};
|
||||||
use edn::symbols;
|
use edn::symbols;
|
||||||
use edn::utils;
|
use edn::utils;
|
||||||
|
|
||||||
|
@ -412,6 +423,11 @@ fn test_value() {
|
||||||
assert_eq!(value("(1)").unwrap(), List(LinkedList::from_iter(vec![Integer(1)])));
|
assert_eq!(value("(1)").unwrap(), List(LinkedList::from_iter(vec![Integer(1)])));
|
||||||
assert_eq!(value("#{1}").unwrap(), Set(BTreeSet::from_iter(vec![Integer(1)])));
|
assert_eq!(value("#{1}").unwrap(), Set(BTreeSet::from_iter(vec![Integer(1)])));
|
||||||
assert_eq!(value("{1 2}").unwrap(), Map(BTreeMap::from_iter(vec![(Integer(1), Integer(2))])));
|
assert_eq!(value("{1 2}").unwrap(), Map(BTreeMap::from_iter(vec![(Integer(1), Integer(2))])));
|
||||||
|
assert_eq!(value("#uuid \"e43c6f3e-3123-49b7-8098-9b47a7bc0fa4\"").unwrap(),
|
||||||
|
Uuid(uuid::Uuid::parse_str("e43c6f3e-3123-49b7-8098-9b47a7bc0fa4").unwrap()));
|
||||||
|
assert_eq!(value("#inst 1493410985187").unwrap(), Instant(UTC.timestamp(1493410985, 187000000)));
|
||||||
|
assert_eq!(value("#inst \"2017-04-28T20:23:05.187Z\"").unwrap(),
|
||||||
|
Instant(UTC.timestamp(1493410985, 187000000)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -55,6 +55,7 @@ impl ConjoiningClauses {
|
||||||
Constant(NonIntegerConstant::Boolean(_)) |
|
Constant(NonIntegerConstant::Boolean(_)) |
|
||||||
Constant(NonIntegerConstant::Text(_)) |
|
Constant(NonIntegerConstant::Text(_)) |
|
||||||
Constant(NonIntegerConstant::Uuid(_)) |
|
Constant(NonIntegerConstant::Uuid(_)) |
|
||||||
|
Constant(NonIntegerConstant::Instant(_)) | // Instants are covered elsewhere.
|
||||||
Constant(NonIntegerConstant::BigInteger(_)) => {
|
Constant(NonIntegerConstant::BigInteger(_)) => {
|
||||||
self.mark_known_empty(EmptyBecause::NonNumericArgument);
|
self.mark_known_empty(EmptyBecause::NonNumericArgument);
|
||||||
bail!(ErrorKind::NonNumericArgument(function.clone(), position));
|
bail!(ErrorKind::NonNumericArgument(function.clone(), position));
|
||||||
|
@ -82,6 +83,7 @@ impl ConjoiningClauses {
|
||||||
Constant(NonIntegerConstant::Float(f)) => Ok(QueryValue::TypedValue(TypedValue::Double(f))),
|
Constant(NonIntegerConstant::Float(f)) => Ok(QueryValue::TypedValue(TypedValue::Double(f))),
|
||||||
Constant(NonIntegerConstant::Text(s)) => Ok(QueryValue::TypedValue(TypedValue::typed_string(s.as_str()))),
|
Constant(NonIntegerConstant::Text(s)) => Ok(QueryValue::TypedValue(TypedValue::typed_string(s.as_str()))),
|
||||||
Constant(NonIntegerConstant::Uuid(u)) => Ok(QueryValue::TypedValue(TypedValue::Uuid(u))),
|
Constant(NonIntegerConstant::Uuid(u)) => Ok(QueryValue::TypedValue(TypedValue::Uuid(u))),
|
||||||
|
Constant(NonIntegerConstant::Instant(u)) => Ok(QueryValue::TypedValue(TypedValue::Instant(u))),
|
||||||
Constant(NonIntegerConstant::BigInteger(_)) => unimplemented!(),
|
Constant(NonIntegerConstant::BigInteger(_)) => unimplemented!(),
|
||||||
SrcVar(_) => unimplemented!(),
|
SrcVar(_) => unimplemented!(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,8 +42,10 @@ use std::rc::Rc;
|
||||||
|
|
||||||
use edn::{
|
use edn::{
|
||||||
BigInt,
|
BigInt,
|
||||||
|
DateTime,
|
||||||
OrderedFloat,
|
OrderedFloat,
|
||||||
Uuid,
|
Uuid,
|
||||||
|
UTC,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use edn::{
|
pub use edn::{
|
||||||
|
@ -186,6 +188,7 @@ pub enum NonIntegerConstant {
|
||||||
BigInteger(BigInt),
|
BigInteger(BigInt),
|
||||||
Float(OrderedFloat<f64>),
|
Float(OrderedFloat<f64>),
|
||||||
Text(Rc<String>),
|
Text(Rc<String>),
|
||||||
|
Instant(DateTime<UTC>),
|
||||||
Uuid(Uuid),
|
Uuid(Uuid),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,6 +199,7 @@ impl NonIntegerConstant {
|
||||||
NonIntegerConstant::Boolean(v) => TypedValue::Boolean(v),
|
NonIntegerConstant::Boolean(v) => TypedValue::Boolean(v),
|
||||||
NonIntegerConstant::Float(v) => TypedValue::Double(v),
|
NonIntegerConstant::Float(v) => TypedValue::Double(v),
|
||||||
NonIntegerConstant::Text(v) => TypedValue::String(v),
|
NonIntegerConstant::Text(v) => TypedValue::String(v),
|
||||||
|
NonIntegerConstant::Instant(v) => TypedValue::Instant(v),
|
||||||
NonIntegerConstant::Uuid(v) => TypedValue::Uuid(v),
|
NonIntegerConstant::Uuid(v) => TypedValue::Uuid(v),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -320,6 +324,8 @@ impl FromValue<PatternValuePlace> for PatternValuePlace {
|
||||||
Some(PatternValuePlace::Constant(NonIntegerConstant::Float(x))),
|
Some(PatternValuePlace::Constant(NonIntegerConstant::Float(x))),
|
||||||
edn::SpannedValue::BigInteger(ref x) =>
|
edn::SpannedValue::BigInteger(ref x) =>
|
||||||
Some(PatternValuePlace::Constant(NonIntegerConstant::BigInteger(x.clone()))),
|
Some(PatternValuePlace::Constant(NonIntegerConstant::BigInteger(x.clone()))),
|
||||||
|
edn::SpannedValue::Instant(x) =>
|
||||||
|
Some(PatternValuePlace::Constant(NonIntegerConstant::Instant(x))),
|
||||||
edn::SpannedValue::Text(ref x) =>
|
edn::SpannedValue::Text(ref x) =>
|
||||||
// TODO: intern strings. #398.
|
// TODO: intern strings. #398.
|
||||||
Some(PatternValuePlace::Constant(NonIntegerConstant::Text(Rc::new(x.clone())))),
|
Some(PatternValuePlace::Constant(NonIntegerConstant::Text(Rc::new(x.clone())))),
|
||||||
|
|
|
@ -19,7 +19,10 @@ use std::rc::Rc;
|
||||||
|
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
|
|
||||||
use mentat_core::TypedValue;
|
use mentat_core::{
|
||||||
|
ToMicros,
|
||||||
|
TypedValue,
|
||||||
|
};
|
||||||
|
|
||||||
pub use rusqlite::types::Value;
|
pub use rusqlite::types::Value;
|
||||||
|
|
||||||
|
@ -140,6 +143,9 @@ impl QueryBuilder for SQLiteQueryBuilder {
|
||||||
&Boolean(v) => self.push_sql(if v { "1" } else { "0" }),
|
&Boolean(v) => self.push_sql(if v { "1" } else { "0" }),
|
||||||
&Long(v) => self.push_sql(v.to_string().as_str()),
|
&Long(v) => self.push_sql(v.to_string().as_str()),
|
||||||
&Double(OrderedFloat(v)) => self.push_sql(v.to_string().as_str()),
|
&Double(OrderedFloat(v)) => self.push_sql(v.to_string().as_str()),
|
||||||
|
&Instant(dt) => {
|
||||||
|
self.push_sql(format!("{}", dt.to_micros()).as_str()); // TODO: argument instead?
|
||||||
|
},
|
||||||
&Uuid(ref u) => {
|
&Uuid(ref u) => {
|
||||||
// Get a byte array.
|
// Get a byte array.
|
||||||
let bytes = u.as_bytes().clone();
|
let bytes = u.as_bytes().clone();
|
||||||
|
|
Loading…
Reference in a new issue