Improve string parsing and allow escaped characters
This commit is contained in:
parent
203b85e6d2
commit
74d8a36056
10 changed files with 146 additions and 59 deletions
|
@ -15,6 +15,14 @@ pub struct Ident {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<String> for Ident {
|
||||||
|
fn from(s: String) -> Self {
|
||||||
|
Ident {
|
||||||
|
name: s,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a str> for Ident {
|
impl<'a> From<&'a str> for Ident {
|
||||||
fn from(i: &str) -> Ident {
|
fn from(i: &str) -> Ident {
|
||||||
Ident {
|
Ident {
|
||||||
|
@ -34,20 +42,24 @@ pub fn ident(i: &str) -> IResult<&str, Ident> {
|
||||||
Ok((i, Ident::from(v)))
|
Ok((i, Ident::from(v)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ident_raw(i: &str) -> IResult<&str, &str> {
|
pub fn ident_raw(i: &str) -> IResult<&str, String> {
|
||||||
alt((ident_default, ident_backtick, ident_brackets))(i)
|
let (i, v) = alt((ident_default, ident_backtick, ident_brackets))(i)?;
|
||||||
|
Ok((i, String::from(v)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ident_default(i: &str) -> IResult<&str, &str> {
|
fn ident_default(i: &str) -> IResult<&str, String> {
|
||||||
take_while1(val_char)(i)
|
let (i, v) = take_while1(val_char)(i)?;
|
||||||
|
Ok((i, String::from(v)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ident_backtick(i: &str) -> IResult<&str, &str> {
|
fn ident_backtick(i: &str) -> IResult<&str, String> {
|
||||||
delimited(tag("`"), is_not("`"), tag("`"))(i)
|
let (i, v) = delimited(tag("`"), is_not("`"), tag("`"))(i)?;
|
||||||
|
Ok((i, String::from(v)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ident_brackets(i: &str) -> IResult<&str, &str> {
|
fn ident_brackets(i: &str) -> IResult<&str, String> {
|
||||||
delimited(tag("⟨"), is_not("⟩"), tag("⟩"))(i)
|
let (i, v) = delimited(tag("⟨"), is_not("⟩"), tag("⟩"))(i)?;
|
||||||
|
Ok((i, String::from(v)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -50,7 +50,7 @@ fn model_count(i: &str) -> IResult<&str, Model> {
|
||||||
Ok((
|
Ok((
|
||||||
i,
|
i,
|
||||||
Model {
|
Model {
|
||||||
table: String::from(t),
|
table: t,
|
||||||
count: Some(c),
|
count: Some(c),
|
||||||
range: None,
|
range: None,
|
||||||
},
|
},
|
||||||
|
@ -68,7 +68,7 @@ fn model_range(i: &str) -> IResult<&str, Model> {
|
||||||
Ok((
|
Ok((
|
||||||
i,
|
i,
|
||||||
Model {
|
Model {
|
||||||
table: String::from(t),
|
table: t,
|
||||||
count: None,
|
count: None,
|
||||||
range: Some((b, e)),
|
range: Some((b, e)),
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,11 +3,9 @@ use crate::dbs::Executor;
|
||||||
use crate::dbs::Runtime;
|
use crate::dbs::Runtime;
|
||||||
use crate::doc::Document;
|
use crate::doc::Document;
|
||||||
use crate::err::Error;
|
use crate::err::Error;
|
||||||
use crate::sql::common::val_char;
|
|
||||||
use crate::sql::idiom::{idiom, Idiom};
|
use crate::sql::idiom::{idiom, Idiom};
|
||||||
use crate::sql::literal::Literal;
|
use crate::sql::literal::Literal;
|
||||||
use nom::bytes::complete::tag;
|
use nom::bytes::complete::tag;
|
||||||
use nom::bytes::complete::take_while1;
|
|
||||||
use nom::IResult;
|
use nom::IResult;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
|
@ -102,7 +102,7 @@ fn namespace(i: &str) -> IResult<&str, DefineNamespaceStatement> {
|
||||||
Ok((
|
Ok((
|
||||||
i,
|
i,
|
||||||
DefineNamespaceStatement {
|
DefineNamespaceStatement {
|
||||||
name: String::from(name),
|
name,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -131,7 +131,7 @@ fn database(i: &str) -> IResult<&str, DefineDatabaseStatement> {
|
||||||
Ok((
|
Ok((
|
||||||
i,
|
i,
|
||||||
DefineDatabaseStatement {
|
DefineDatabaseStatement {
|
||||||
name: String::from(name),
|
name,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -177,7 +177,7 @@ fn login(i: &str) -> IResult<&str, DefineLoginStatement> {
|
||||||
Ok((
|
Ok((
|
||||||
i,
|
i,
|
||||||
DefineLoginStatement {
|
DefineLoginStatement {
|
||||||
name: String::from(name),
|
name,
|
||||||
base,
|
base,
|
||||||
pass: match opts {
|
pass: match opts {
|
||||||
DefineLoginOption::Password(ref v) => Some(v.to_owned()),
|
DefineLoginOption::Password(ref v) => Some(v.to_owned()),
|
||||||
|
@ -206,7 +206,7 @@ fn login_pass(i: &str) -> IResult<&str, DefineLoginOption> {
|
||||||
let (i, _) = tag_no_case("PASSWORD")(i)?;
|
let (i, _) = tag_no_case("PASSWORD")(i)?;
|
||||||
let (i, _) = shouldbespace(i)?;
|
let (i, _) = shouldbespace(i)?;
|
||||||
let (i, v) = strand_raw(i)?;
|
let (i, v) = strand_raw(i)?;
|
||||||
Ok((i, DefineLoginOption::Password(String::from(v))))
|
Ok((i, DefineLoginOption::Password(v)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn login_hash(i: &str) -> IResult<&str, DefineLoginOption> {
|
fn login_hash(i: &str) -> IResult<&str, DefineLoginOption> {
|
||||||
|
@ -214,7 +214,7 @@ fn login_hash(i: &str) -> IResult<&str, DefineLoginOption> {
|
||||||
let (i, _) = tag_no_case("PASSHASH")(i)?;
|
let (i, _) = tag_no_case("PASSHASH")(i)?;
|
||||||
let (i, _) = shouldbespace(i)?;
|
let (i, _) = shouldbespace(i)?;
|
||||||
let (i, v) = strand_raw(i)?;
|
let (i, v) = strand_raw(i)?;
|
||||||
Ok((i, DefineLoginOption::Passhash(String::from(v))))
|
Ok((i, DefineLoginOption::Passhash(v)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------
|
// --------------------------------------------------
|
||||||
|
@ -260,10 +260,10 @@ fn token(i: &str) -> IResult<&str, DefineTokenStatement> {
|
||||||
Ok((
|
Ok((
|
||||||
i,
|
i,
|
||||||
DefineTokenStatement {
|
DefineTokenStatement {
|
||||||
name: String::from(name),
|
name,
|
||||||
base,
|
base,
|
||||||
kind,
|
kind,
|
||||||
code: String::from(code),
|
code,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -314,7 +314,7 @@ fn scope(i: &str) -> IResult<&str, DefineScopeStatement> {
|
||||||
Ok((
|
Ok((
|
||||||
i,
|
i,
|
||||||
DefineScopeStatement {
|
DefineScopeStatement {
|
||||||
name: String::from(name),
|
name,
|
||||||
session: opts.iter().find_map(|x| match x {
|
session: opts.iter().find_map(|x| match x {
|
||||||
DefineScopeOption::Session(ref v) => Some(v.to_owned()),
|
DefineScopeOption::Session(ref v) => Some(v.to_owned()),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -423,7 +423,7 @@ fn table(i: &str) -> IResult<&str, DefineTableStatement> {
|
||||||
Ok((
|
Ok((
|
||||||
i,
|
i,
|
||||||
DefineTableStatement {
|
DefineTableStatement {
|
||||||
name: String::from(name),
|
name,
|
||||||
drop: opts
|
drop: opts
|
||||||
.iter()
|
.iter()
|
||||||
.find_map(|x| match x {
|
.find_map(|x| match x {
|
||||||
|
@ -540,8 +540,8 @@ fn event(i: &str) -> IResult<&str, DefineEventStatement> {
|
||||||
Ok((
|
Ok((
|
||||||
i,
|
i,
|
||||||
DefineEventStatement {
|
DefineEventStatement {
|
||||||
name: String::from(name),
|
name,
|
||||||
what: String::from(what),
|
what,
|
||||||
when,
|
when,
|
||||||
then,
|
then,
|
||||||
},
|
},
|
||||||
|
@ -599,7 +599,7 @@ fn field(i: &str) -> IResult<&str, DefineFieldStatement> {
|
||||||
i,
|
i,
|
||||||
DefineFieldStatement {
|
DefineFieldStatement {
|
||||||
name,
|
name,
|
||||||
what: String::from(what),
|
what,
|
||||||
kind: opts.iter().find_map(|x| match x {
|
kind: opts.iter().find_map(|x| match x {
|
||||||
DefineFieldOption::Kind(ref v) => Some(v.to_owned()),
|
DefineFieldOption::Kind(ref v) => Some(v.to_owned()),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -722,8 +722,8 @@ fn index(i: &str) -> IResult<&str, DefineIndexStatement> {
|
||||||
Ok((
|
Ok((
|
||||||
i,
|
i,
|
||||||
DefineIndexStatement {
|
DefineIndexStatement {
|
||||||
name: String::from(name),
|
name,
|
||||||
what: String::from(what),
|
what,
|
||||||
cols,
|
cols,
|
||||||
uniq: uniq.is_some(),
|
uniq: uniq.is_some(),
|
||||||
},
|
},
|
||||||
|
|
|
@ -64,14 +64,14 @@ fn scope(i: &str) -> IResult<&str, InfoStatement> {
|
||||||
let (i, _) = alt((tag_no_case("SCOPE"), tag_no_case("SC")))(i)?;
|
let (i, _) = alt((tag_no_case("SCOPE"), tag_no_case("SC")))(i)?;
|
||||||
let (i, _) = shouldbespace(i)?;
|
let (i, _) = shouldbespace(i)?;
|
||||||
let (i, scope) = ident_raw(i)?;
|
let (i, scope) = ident_raw(i)?;
|
||||||
Ok((i, InfoStatement::Scope(String::from(scope))))
|
Ok((i, InfoStatement::Scope(scope)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn table(i: &str) -> IResult<&str, InfoStatement> {
|
fn table(i: &str) -> IResult<&str, InfoStatement> {
|
||||||
let (i, _) = alt((tag_no_case("TABLE"), tag_no_case("TB")))(i)?;
|
let (i, _) = alt((tag_no_case("TABLE"), tag_no_case("TB")))(i)?;
|
||||||
let (i, _) = shouldbespace(i)?;
|
let (i, _) = shouldbespace(i)?;
|
||||||
let (i, table) = ident_raw(i)?;
|
let (i, table) = ident_raw(i)?;
|
||||||
Ok((i, InfoStatement::Table(String::from(table))))
|
Ok((i, InfoStatement::Table(table)))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -92,7 +92,7 @@ fn namespace(i: &str) -> IResult<&str, RemoveNamespaceStatement> {
|
||||||
Ok((
|
Ok((
|
||||||
i,
|
i,
|
||||||
RemoveNamespaceStatement {
|
RemoveNamespaceStatement {
|
||||||
name: String::from(name),
|
name,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,7 @@ fn database(i: &str) -> IResult<&str, RemoveDatabaseStatement> {
|
||||||
Ok((
|
Ok((
|
||||||
i,
|
i,
|
||||||
RemoveDatabaseStatement {
|
RemoveDatabaseStatement {
|
||||||
name: String::from(name),
|
name,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -155,7 +155,7 @@ fn login(i: &str) -> IResult<&str, RemoveLoginStatement> {
|
||||||
Ok((
|
Ok((
|
||||||
i,
|
i,
|
||||||
RemoveLoginStatement {
|
RemoveLoginStatement {
|
||||||
name: String::from(name),
|
name,
|
||||||
base,
|
base,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
|
@ -190,7 +190,7 @@ fn token(i: &str) -> IResult<&str, RemoveTokenStatement> {
|
||||||
Ok((
|
Ok((
|
||||||
i,
|
i,
|
||||||
RemoveTokenStatement {
|
RemoveTokenStatement {
|
||||||
name: String::from(name),
|
name,
|
||||||
base,
|
base,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
|
@ -220,7 +220,7 @@ fn scope(i: &str) -> IResult<&str, RemoveScopeStatement> {
|
||||||
Ok((
|
Ok((
|
||||||
i,
|
i,
|
||||||
RemoveScopeStatement {
|
RemoveScopeStatement {
|
||||||
name: String::from(name),
|
name,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -249,7 +249,7 @@ fn table(i: &str) -> IResult<&str, RemoveTableStatement> {
|
||||||
Ok((
|
Ok((
|
||||||
i,
|
i,
|
||||||
RemoveTableStatement {
|
RemoveTableStatement {
|
||||||
name: String::from(name),
|
name,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -283,8 +283,8 @@ fn event(i: &str) -> IResult<&str, RemoveEventStatement> {
|
||||||
Ok((
|
Ok((
|
||||||
i,
|
i,
|
||||||
RemoveEventStatement {
|
RemoveEventStatement {
|
||||||
name: String::from(name),
|
name,
|
||||||
what: String::from(what),
|
what,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -318,8 +318,8 @@ fn field(i: &str) -> IResult<&str, RemoveFieldStatement> {
|
||||||
Ok((
|
Ok((
|
||||||
i,
|
i,
|
||||||
RemoveFieldStatement {
|
RemoveFieldStatement {
|
||||||
name: String::from(name),
|
name,
|
||||||
what: String::from(what),
|
what,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -353,8 +353,8 @@ fn index(i: &str) -> IResult<&str, RemoveIndexStatement> {
|
||||||
Ok((
|
Ok((
|
||||||
i,
|
i,
|
||||||
RemoveIndexStatement {
|
RemoveIndexStatement {
|
||||||
name: String::from(name),
|
name,
|
||||||
what: String::from(what),
|
what,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,8 +61,8 @@ fn both(i: &str) -> IResult<&str, UseStatement> {
|
||||||
Ok((
|
Ok((
|
||||||
i,
|
i,
|
||||||
UseStatement {
|
UseStatement {
|
||||||
ns: Some(String::from(ns)),
|
ns: Some(ns),
|
||||||
db: Some(String::from(db)),
|
db: Some(db),
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ fn ns(i: &str) -> IResult<&str, UseStatement> {
|
||||||
Ok((
|
Ok((
|
||||||
i,
|
i,
|
||||||
UseStatement {
|
UseStatement {
|
||||||
ns: Some(String::from(ns)),
|
ns: Some(ns),
|
||||||
db: None,
|
db: None,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
|
@ -92,7 +92,7 @@ fn db(i: &str) -> IResult<&str, UseStatement> {
|
||||||
i,
|
i,
|
||||||
UseStatement {
|
UseStatement {
|
||||||
ns: None,
|
ns: None,
|
||||||
db: Some(String::from(db)),
|
db: Some(db),
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,20 @@
|
||||||
use nom::branch::alt;
|
use nom::branch::alt;
|
||||||
|
use nom::bytes::complete::escaped;
|
||||||
use nom::bytes::complete::is_not;
|
use nom::bytes::complete::is_not;
|
||||||
use nom::bytes::complete::tag;
|
use nom::bytes::complete::tag;
|
||||||
use nom::sequence::delimited;
|
use nom::character::complete::one_of;
|
||||||
use nom::IResult;
|
use nom::IResult;
|
||||||
use serde::ser::SerializeStruct;
|
use serde::ser::SerializeStruct;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
|
const SINGLE: &str = r#"'"#;
|
||||||
|
const SINGLE_ESC: &str = r#"\'"#;
|
||||||
|
|
||||||
|
const DOUBLE: &str = r#"""#;
|
||||||
|
const DOUBLE_ESC: &str = r#"\""#;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Deserialize)]
|
||||||
pub struct Strand {
|
pub struct Strand {
|
||||||
pub value: String,
|
pub value: String,
|
||||||
|
@ -55,14 +62,76 @@ pub fn strand(i: &str) -> IResult<&str, Strand> {
|
||||||
Ok((i, Strand::from(v)))
|
Ok((i, Strand::from(v)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn strand_raw(i: &str) -> IResult<&str, &str> {
|
pub fn strand_raw(i: &str) -> IResult<&str, String> {
|
||||||
alt((strand_single, strand_double))(i)
|
alt((strand_single, strand_double))(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn strand_single(i: &str) -> IResult<&str, &str> {
|
fn strand_single(i: &str) -> IResult<&str, String> {
|
||||||
delimited(tag("\'"), is_not("\'"), tag("\'"))(i)
|
let (i, _) = tag(SINGLE)(i)?;
|
||||||
|
let (i, v) = alt((escaped(is_not(SINGLE_ESC), '\\', one_of(SINGLE)), tag("")))(i)?;
|
||||||
|
let (i, _) = tag(SINGLE)(i)?;
|
||||||
|
Ok((i, String::from(v).replace(SINGLE_ESC, SINGLE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn strand_double(i: &str) -> IResult<&str, &str> {
|
fn strand_double(i: &str) -> IResult<&str, String> {
|
||||||
delimited(tag("\""), is_not("\""), tag("\""))(i)
|
let (i, _) = tag(DOUBLE)(i)?;
|
||||||
|
let (i, v) = alt((escaped(is_not(DOUBLE_ESC), '\\', one_of(DOUBLE)), tag("")))(i)?;
|
||||||
|
let (i, _) = tag(DOUBLE)(i)?;
|
||||||
|
Ok((i, String::from(v).replace(DOUBLE_ESC, DOUBLE)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn strand_empty() {
|
||||||
|
let sql = r#""""#;
|
||||||
|
let res = strand(sql);
|
||||||
|
assert!(res.is_ok());
|
||||||
|
let out = res.unwrap().1;
|
||||||
|
assert_eq!(r#""""#, format!("{}", out));
|
||||||
|
assert_eq!(out, Strand::from(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn strand_single() {
|
||||||
|
let sql = r#"'test'"#;
|
||||||
|
let res = strand(sql);
|
||||||
|
assert!(res.is_ok());
|
||||||
|
let out = res.unwrap().1;
|
||||||
|
assert_eq!(r#""test""#, format!("{}", out));
|
||||||
|
assert_eq!(out, Strand::from("test"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn strand_double() {
|
||||||
|
let sql = r#""test""#;
|
||||||
|
let res = strand(sql);
|
||||||
|
assert!(res.is_ok());
|
||||||
|
let out = res.unwrap().1;
|
||||||
|
assert_eq!(r#""test""#, format!("{}", out));
|
||||||
|
assert_eq!(out, Strand::from("test"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn strand_quoted_single() {
|
||||||
|
let sql = r#"'te\'st'"#;
|
||||||
|
let res = strand(sql);
|
||||||
|
assert!(res.is_ok());
|
||||||
|
let out = res.unwrap().1;
|
||||||
|
assert_eq!(r#""te'st""#, format!("{}", out));
|
||||||
|
assert_eq!(out, Strand::from(r#"te'st"#));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn strand_quoted_double() {
|
||||||
|
let sql = r#""te\"st""#;
|
||||||
|
let res = strand(sql);
|
||||||
|
assert!(res.is_ok());
|
||||||
|
let out = res.unwrap().1;
|
||||||
|
assert_eq!(r#""te"st""#, format!("{}", out));
|
||||||
|
assert_eq!(out, Strand::from(r#"te"st"#));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,14 @@ pub struct Table {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<String> for Table {
|
||||||
|
fn from(s: String) -> Self {
|
||||||
|
Table {
|
||||||
|
name: s,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a str> for Table {
|
impl<'a> From<&'a str> for Table {
|
||||||
fn from(t: &str) -> Table {
|
fn from(t: &str) -> Table {
|
||||||
Table {
|
Table {
|
||||||
|
|
|
@ -9,13 +9,13 @@ use std::fmt;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Deserialize)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq, PartialOrd, Deserialize)]
|
||||||
pub struct Thing {
|
pub struct Thing {
|
||||||
pub table: String,
|
pub tb: String,
|
||||||
pub id: String,
|
pub id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Thing {
|
impl fmt::Display for Thing {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
let t = escape(&self.table, &val_char, "`");
|
let t = escape(&self.tb, &val_char, "`");
|
||||||
let i = escape(&self.id, &val_char, "`");
|
let i = escape(&self.id, &val_char, "`");
|
||||||
write!(f, "{}:{}", t, i)
|
write!(f, "{}:{}", t, i)
|
||||||
}
|
}
|
||||||
|
@ -27,11 +27,11 @@ impl Serialize for Thing {
|
||||||
S: serde::Serializer,
|
S: serde::Serializer,
|
||||||
{
|
{
|
||||||
if serializer.is_human_readable() {
|
if serializer.is_human_readable() {
|
||||||
let output = format!("{}:{}", self.table, self.id);
|
let output = format!("{}:{}", self.tb, self.id);
|
||||||
serializer.serialize_some(&output)
|
serializer.serialize_some(&output)
|
||||||
} else {
|
} else {
|
||||||
let mut val = serializer.serialize_struct("Thing", 2)?;
|
let mut val = serializer.serialize_struct("Thing", 2)?;
|
||||||
val.serialize_field("table", &self.table)?;
|
val.serialize_field("tb", &self.tb)?;
|
||||||
val.serialize_field("id", &self.id)?;
|
val.serialize_field("id", &self.id)?;
|
||||||
val.end()
|
val.end()
|
||||||
}
|
}
|
||||||
|
@ -45,8 +45,8 @@ pub fn thing(i: &str) -> IResult<&str, Thing> {
|
||||||
Ok((
|
Ok((
|
||||||
i,
|
i,
|
||||||
Thing {
|
Thing {
|
||||||
table: String::from(t),
|
tb: t,
|
||||||
id: String::from(v),
|
id: v,
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
out,
|
out,
|
||||||
Thing {
|
Thing {
|
||||||
table: String::from("test"),
|
tb: String::from("test"),
|
||||||
id: String::from("id"),
|
id: String::from("id"),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -82,7 +82,7 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
out,
|
out,
|
||||||
Thing {
|
Thing {
|
||||||
table: String::from("test"),
|
tb: String::from("test"),
|
||||||
id: String::from("id"),
|
id: String::from("id"),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -98,7 +98,7 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
out,
|
out,
|
||||||
Thing {
|
Thing {
|
||||||
table: String::from("test"),
|
tb: String::from("test"),
|
||||||
id: String::from("id"),
|
id: String::from("id"),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue