Add pretty printing for SQL Query
, Statement
, Value
, Array
, and Object
types (#1420)
This commit is contained in:
parent
79d6107b4e
commit
a1b9201bbd
10 changed files with 405 additions and 80 deletions
|
@ -5,7 +5,7 @@ use crate::err::Error;
|
|||
use crate::sql::comment::mightbespace;
|
||||
use crate::sql::common::commas;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::fmt::Fmt;
|
||||
use crate::sql::fmt::{pretty_indent, Fmt, Pretty};
|
||||
use crate::sql::number::Number;
|
||||
use crate::sql::operation::Operation;
|
||||
use crate::sql::serde::is_internal_serialization;
|
||||
|
@ -16,7 +16,7 @@ use nom::combinator::opt;
|
|||
use nom::multi::separated_list0;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashSet;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::fmt::{self, Display, Formatter, Write};
|
||||
use std::ops;
|
||||
use std::ops::Deref;
|
||||
use std::ops::DerefMut;
|
||||
|
@ -148,7 +148,12 @@ impl Array {
|
|||
|
||||
impl Display for Array {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "[{}]", Fmt::comma_separated(self.as_slice()))
|
||||
let mut f = Pretty::from(f);
|
||||
f.write_char('[')?;
|
||||
let indent = pretty_indent();
|
||||
write!(f, "{}", Fmt::pretty_comma_separated(self.as_slice()))?;
|
||||
drop(indent);
|
||||
f.write_char(']')
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::cell::Cell;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::fmt::{self, Display, Formatter, Write};
|
||||
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
|
||||
|
||||
/// Implements fmt::Display by calling formatter on contents.
|
||||
pub(crate) struct Fmt<T, F> {
|
||||
|
@ -29,6 +30,24 @@ impl<I: IntoIterator<Item = T>, T: Display> Fmt<I, fn(I, &mut Formatter) -> fmt:
|
|||
pub(crate) fn comma_separated(into_iter: I) -> Self {
|
||||
Self::new(into_iter, fmt_comma_separated)
|
||||
}
|
||||
|
||||
/// Formats values with a comma and a space separating them or, if pretty printing is in
|
||||
/// effect, a comma, a newline, and indentation.
|
||||
pub(crate) fn pretty_comma_separated(into_iter: I) -> Self {
|
||||
Self::new(
|
||||
into_iter,
|
||||
if is_pretty() {
|
||||
fmt_pretty_comma_separated
|
||||
} else {
|
||||
fmt_comma_separated
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
/// Formats values with a new line separating them.
|
||||
pub(crate) fn pretty_new_line_separated(into_iter: I) -> Self {
|
||||
Self::new(into_iter, fmt_new_line_separated)
|
||||
}
|
||||
}
|
||||
|
||||
fn fmt_comma_separated<T: Display>(
|
||||
|
@ -37,9 +56,231 @@ fn fmt_comma_separated<T: Display>(
|
|||
) -> fmt::Result {
|
||||
for (i, v) in into_iter.into_iter().enumerate() {
|
||||
if i > 0 {
|
||||
// This comma goes after the item formatted in the last iteration.
|
||||
f.write_str(", ")?;
|
||||
}
|
||||
Display::fmt(&v, f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fmt_pretty_comma_separated<T: Display>(
|
||||
into_iter: impl IntoIterator<Item = T>,
|
||||
f: &mut Formatter,
|
||||
) -> fmt::Result {
|
||||
for (i, v) in into_iter.into_iter().enumerate() {
|
||||
if i > 0 {
|
||||
// We don't need a space after the comma if we are going to have a newline.
|
||||
f.write_char(',')?;
|
||||
pretty_sequence_item();
|
||||
}
|
||||
Display::fmt(&v, f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fmt_new_line_separated<T: Display>(
|
||||
into_iter: impl IntoIterator<Item = T>,
|
||||
f: &mut Formatter,
|
||||
) -> fmt::Result {
|
||||
for (i, v) in into_iter.into_iter().enumerate() {
|
||||
if i > 0 {
|
||||
// One of the few cases where the raw string data depends on is pretty i.e. we don't
|
||||
// need a space after the comma if we are going to have a newline.
|
||||
if is_pretty() {
|
||||
pretty_sequence_item();
|
||||
} else {
|
||||
f.write_char('\n')?;
|
||||
}
|
||||
}
|
||||
Display::fmt(&v, f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Creates a formatting function that joins iterators with an arbitrary separator.
|
||||
pub fn fmt_separated_by<T: Display, II: IntoIterator<Item = T>>(
|
||||
separator: impl Display,
|
||||
) -> impl Fn(II, &mut Formatter) -> fmt::Result {
|
||||
move |into_iter: II, f: &mut Formatter| {
|
||||
for (i, v) in into_iter.into_iter().enumerate() {
|
||||
if i > 0 {
|
||||
// This separator goes after the item formatted in the last iteration.
|
||||
Display::fmt(&separator, f)?;
|
||||
}
|
||||
Display::fmt(&v, f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
// Avoid `RefCell`/`UnsafeCell` by using atomic types. Access is synchronized due to
|
||||
// `thread_local!` so all accesses can use `Ordering::Relaxed`.
|
||||
|
||||
/// Whether pretty-printing.
|
||||
static PRETTY: AtomicBool = AtomicBool::new(false);
|
||||
/// The current level of indentation, in units of tabs.
|
||||
static INDENT: AtomicU32 = AtomicU32::new(0);
|
||||
/// Whether the next formatting action should be preceded by a newline and indentation.
|
||||
static NEW_LINE: AtomicBool = AtomicBool::new(false);
|
||||
}
|
||||
|
||||
/// An adapter that, if enabled, adds pretty print formatting.
|
||||
pub(crate) struct Pretty<W: std::fmt::Write> {
|
||||
inner: W,
|
||||
/// This is the active pretty printer, responsible for injecting formatting.
|
||||
active: bool,
|
||||
}
|
||||
|
||||
impl<W: std::fmt::Write> Pretty<W> {
|
||||
#[allow(unused)]
|
||||
pub fn new(inner: W) -> Self {
|
||||
Self::conditional(inner, true)
|
||||
}
|
||||
|
||||
pub fn conditional(inner: W, enable: bool) -> Self {
|
||||
let pretty_started_here = enable
|
||||
&& PRETTY.with(|pretty| {
|
||||
// Evaluates to true if PRETTY was false and is now true.
|
||||
pretty.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed).is_ok()
|
||||
});
|
||||
if pretty_started_here {
|
||||
// Clean slate.
|
||||
NEW_LINE.with(|new_line| new_line.store(false, Ordering::Relaxed));
|
||||
INDENT.with(|indent| indent.store(0, Ordering::Relaxed));
|
||||
}
|
||||
Self {
|
||||
inner,
|
||||
// Don't want multiple active pretty printers, although they wouldn't necessarily misbehave.
|
||||
active: pretty_started_here,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> From<&'a mut Formatter<'b>> for Pretty<&'a mut Formatter<'b>> {
|
||||
fn from(f: &'a mut Formatter<'b>) -> Self {
|
||||
Self::conditional(f, f.alternate())
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: std::fmt::Write> Drop for Pretty<W> {
|
||||
fn drop(&mut self) {
|
||||
if self.active {
|
||||
PRETTY.with(|pretty| {
|
||||
debug_assert!(pretty.load(Ordering::Relaxed), "pretty status changed unexpectedly");
|
||||
pretty.store(false, Ordering::Relaxed);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether pretty printing is in effect.
|
||||
pub(crate) fn is_pretty() -> bool {
|
||||
PRETTY.with(|pretty| pretty.load(Ordering::Relaxed))
|
||||
}
|
||||
|
||||
/// If pretty printing is in effect, increments the indentation level (until the return value
|
||||
/// is dropped).
|
||||
#[must_use = "hold for the span of the indent, then drop"]
|
||||
pub(crate) fn pretty_indent() -> PrettyGuard {
|
||||
PrettyGuard::new(1)
|
||||
}
|
||||
|
||||
/// Marks the end of an item in the sequence, after which indentation will follow if pretty printing
|
||||
/// is in effect.
|
||||
pub(crate) fn pretty_sequence_item() {
|
||||
// List items need a new line, but no additional indentation.
|
||||
NEW_LINE.with(|new_line| new_line.store(true, Ordering::Relaxed));
|
||||
}
|
||||
|
||||
/// When dropped, applies the opposite increment to the current indentation level.
|
||||
pub(crate) struct PrettyGuard {
|
||||
increment: i8,
|
||||
}
|
||||
|
||||
impl PrettyGuard {
|
||||
fn new(increment: i8) -> Self {
|
||||
Self::raw(increment);
|
||||
PrettyGuard {
|
||||
increment,
|
||||
}
|
||||
}
|
||||
|
||||
fn raw(increment: i8) {
|
||||
INDENT.with(|indent| {
|
||||
// Equivalent to `indent += increment` if signed numbers could be added to unsigned
|
||||
// numbers in stable, atomic Rust.
|
||||
if increment >= 0 {
|
||||
indent.fetch_add(increment as u32, Ordering::Relaxed);
|
||||
} else {
|
||||
indent.fetch_sub(increment.unsigned_abs() as u32, Ordering::Relaxed);
|
||||
}
|
||||
});
|
||||
NEW_LINE.with(|new_line| new_line.store(true, Ordering::Relaxed));
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for PrettyGuard {
|
||||
fn drop(&mut self) {
|
||||
Self::raw(-self.increment)
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: std::fmt::Write> std::fmt::Write for Pretty<W> {
|
||||
fn write_str(&mut self, s: &str) -> std::fmt::Result {
|
||||
if self.active && NEW_LINE.with(|new_line| new_line.swap(false, Ordering::Relaxed)) {
|
||||
// Newline.
|
||||
self.inner.write_char('\n')?;
|
||||
for _ in 0..INDENT.with(|indent| indent.load(Ordering::Relaxed)) {
|
||||
// One level of indentation.
|
||||
self.inner.write_char('\t')?;
|
||||
}
|
||||
}
|
||||
// What we were asked to write.
|
||||
self.inner.write_str(s)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::sql::{array::array, object::object, parse, value::value};
|
||||
|
||||
#[test]
|
||||
fn pretty_query() {
|
||||
let query = parse("SELECT * FROM {foo: [1, 2, 3]};").unwrap();
|
||||
assert_eq!(format!("{}", query), "SELECT * FROM { foo: [1, 2, 3] };");
|
||||
assert_eq!(
|
||||
format!("{:#}", query),
|
||||
"SELECT * FROM {\n\tfoo: [\n\t\t1,\n\t\t2,\n\t\t3\n\t]\n};"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pretty_define_query() {
|
||||
let query = parse("DEFINE TABLE test SCHEMAFULL PERMISSIONS FOR create, update, delete NONE FOR select WHERE public = true;").unwrap();
|
||||
assert_eq!(format!("{}", query), "DEFINE TABLE test SCHEMAFULL PERMISSIONS FOR select WHERE public = true, FOR create, update, delete NONE;");
|
||||
assert_eq!(format!("{:#}", query), "DEFINE TABLE test SCHEMAFULL\n\tPERMISSIONS\n\t\tFOR select\n\t\t\tWHERE public = true\n\t\tFOR create, update, delete NONE\n;");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pretty_value() {
|
||||
let value = value("{foo: [1, 2, 3]};").unwrap().1;
|
||||
assert_eq!(format!("{}", value), "{ foo: [1, 2, 3] }");
|
||||
assert_eq!(format!("{:#}", value), "{\n\tfoo: [\n\t\t1,\n\t\t2,\n\t\t3\n\t]\n}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pretty_object() {
|
||||
let object = object("{foo: [1, 2, 3]};").unwrap().1;
|
||||
assert_eq!(format!("{}", object), "{ foo: [1, 2, 3] }");
|
||||
assert_eq!(format!("{:#}", object), "{\n\tfoo: [\n\t\t1,\n\t\t2,\n\t\t3\n\t]\n}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pretty_array() {
|
||||
let array = array("[1, 2, 3];").unwrap().1;
|
||||
assert_eq!(format!("{}", array), "[1, 2, 3]");
|
||||
assert_eq!(format!("{:#}", array), "[\n\t1,\n\t2,\n\t3\n]");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::dbs::Transaction;
|
|||
use crate::err::Error;
|
||||
use crate::sql::common::commas;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::fmt::Fmt;
|
||||
use crate::sql::fmt::{fmt_separated_by, Fmt};
|
||||
use crate::sql::part::Next;
|
||||
use crate::sql::part::{all, field, first, graph, index, last, part, thing, Part};
|
||||
use crate::sql::paths::{ID, IN, OUT};
|
||||
|
@ -147,18 +147,17 @@ impl Idiom {
|
|||
|
||||
impl fmt::Display for Idiom {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
self.0
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, p)| match (i, p) {
|
||||
(0, Part::Field(v)) => format!("{}", v),
|
||||
_ => format!("{}", p),
|
||||
Display::fmt(
|
||||
&Fmt::new(
|
||||
self.0.iter().enumerate().map(|args| {
|
||||
Fmt::new(args, |(i, p), f| match (i, p) {
|
||||
(0, Part::Field(v)) => Display::fmt(v, f),
|
||||
_ => Display::fmt(p, f),
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("")
|
||||
}),
|
||||
fmt_separated_by(""),
|
||||
),
|
||||
f,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::sql::comment::mightbespace;
|
|||
use crate::sql::common::{commas, val_char};
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::escape::escape_key;
|
||||
use crate::sql::fmt::Fmt;
|
||||
use crate::sql::fmt::{is_pretty, pretty_indent, Fmt, Pretty};
|
||||
use crate::sql::operation::{Op, Operation};
|
||||
use crate::sql::serde::is_internal_serialization;
|
||||
use crate::sql::thing::Thing;
|
||||
|
@ -22,7 +22,7 @@ use serde::ser::SerializeMap;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::fmt::{self, Display, Formatter, Write};
|
||||
use std::ops::Deref;
|
||||
use std::ops::DerefMut;
|
||||
|
||||
|
@ -134,17 +134,33 @@ impl Object {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Object {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
impl Display for Object {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
let mut f = Pretty::from(f);
|
||||
if is_pretty() {
|
||||
f.write_char('{')?;
|
||||
} else {
|
||||
f.write_str("{ ")?;
|
||||
}
|
||||
let indent = pretty_indent();
|
||||
write!(
|
||||
f,
|
||||
"{{ {} }}",
|
||||
Fmt::comma_separated(
|
||||
self.0.iter().map(|args| Fmt::new(args, |(k, v), f| {
|
||||
write!(f, "{}: {}", escape_key(k), v)
|
||||
}))
|
||||
)
|
||||
"{}",
|
||||
Fmt::pretty_comma_separated(
|
||||
self.0.iter().map(|args| Fmt::new(args, |(k, v), f| write!(
|
||||
f,
|
||||
"{}: {}",
|
||||
escape_key(k),
|
||||
v
|
||||
))),
|
||||
)
|
||||
)?;
|
||||
drop(indent);
|
||||
if is_pretty() {
|
||||
f.write_char('}')
|
||||
} else {
|
||||
f.write_str(" }")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,13 +2,17 @@ use crate::sql::comment::shouldbespace;
|
|||
use crate::sql::common::commas;
|
||||
use crate::sql::common::commasorspace;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::fmt::is_pretty;
|
||||
use crate::sql::fmt::pretty_indent;
|
||||
use crate::sql::fmt::pretty_sequence_item;
|
||||
use crate::sql::value::{value, Value};
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
use nom::combinator::map;
|
||||
use nom::{multi::separated_list0, sequence::tuple};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::fmt::Write;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::str;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Hash)]
|
||||
|
@ -53,8 +57,8 @@ impl Permissions {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Permissions {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
impl Display for Permissions {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "PERMISSIONS")?;
|
||||
if self.is_none() {
|
||||
return write!(f, " NONE");
|
||||
|
@ -62,11 +66,56 @@ impl fmt::Display for Permissions {
|
|||
if self.is_full() {
|
||||
return write!(f, " FULL");
|
||||
}
|
||||
write!(
|
||||
f,
|
||||
" FOR select {}, FOR create {}, FOR update {}, FOR delete {}",
|
||||
self.select, self.create, self.update, self.delete
|
||||
)
|
||||
let mut lines = Vec::<(Vec<char>, &Permission)>::new();
|
||||
for (c, permission) in ['s', 'c', 'u', 'd'].into_iter().zip([
|
||||
&self.select,
|
||||
&self.create,
|
||||
&self.update,
|
||||
&self.delete,
|
||||
]) {
|
||||
if let Some((existing, _)) = lines.iter_mut().find(|(_, p)| *p == permission) {
|
||||
existing.push(c);
|
||||
} else {
|
||||
lines.push((vec![c], permission));
|
||||
}
|
||||
}
|
||||
let indent = if is_pretty() {
|
||||
Some(pretty_indent())
|
||||
} else {
|
||||
f.write_char(' ')?;
|
||||
None
|
||||
};
|
||||
for (i, (kinds, permission)) in lines.into_iter().enumerate() {
|
||||
if i > 0 {
|
||||
if is_pretty() {
|
||||
pretty_sequence_item();
|
||||
} else {
|
||||
f.write_str(", ")?;
|
||||
}
|
||||
}
|
||||
write!(f, "FOR ")?;
|
||||
for (i, kind) in kinds.into_iter().enumerate() {
|
||||
if i > 0 {
|
||||
f.write_str(", ")?;
|
||||
}
|
||||
f.write_str(match kind {
|
||||
's' => "select",
|
||||
'c' => "create",
|
||||
'u' => "update",
|
||||
'd' => "delete",
|
||||
_ => unreachable!(),
|
||||
})?;
|
||||
}
|
||||
match permission {
|
||||
Permission::Specific(_) if is_pretty() => {
|
||||
let _indent = pretty_indent();
|
||||
Display::fmt(permission, f)?;
|
||||
}
|
||||
_ => write!(f, " {}", permission)?,
|
||||
}
|
||||
}
|
||||
drop(indent);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,8 +193,8 @@ impl Default for Permission {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Permission {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
impl Display for Permission {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::None => f.write_str("NONE"),
|
||||
Self::Full => f.write_str("FULL"),
|
||||
|
@ -212,7 +261,7 @@ mod tests {
|
|||
assert!(res.is_ok());
|
||||
let out = res.unwrap().1;
|
||||
assert_eq!(
|
||||
"PERMISSIONS FOR select FULL, FOR create WHERE public = true, FOR update WHERE public = true, FOR delete NONE",
|
||||
"PERMISSIONS FOR select FULL, FOR create, update WHERE public = true, FOR delete NONE",
|
||||
format!("{}", out)
|
||||
);
|
||||
assert_eq!(
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
use crate::sql::error::IResult;
|
||||
use crate::sql::fmt::Pretty;
|
||||
use crate::sql::statement::{statements, Statement, Statements};
|
||||
use derive::Store;
|
||||
use nom::combinator::all_consuming;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Write;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::ops::Deref;
|
||||
use std::str;
|
||||
|
@ -19,7 +21,7 @@ impl Deref for Query {
|
|||
|
||||
impl Display for Query {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
Display::fmt(&self.0, f)
|
||||
write!(Pretty::from(f), "{}", &self.0)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ use crate::err::Error;
|
|||
use crate::sql::comment::{comment, mightbespace};
|
||||
use crate::sql::common::colons;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::fmt::Fmt;
|
||||
use crate::sql::fmt::Pretty;
|
||||
use crate::sql::statements::begin::{begin, BeginStatement};
|
||||
use crate::sql::statements::cancel::{cancel, CancelStatement};
|
||||
use crate::sql::statements::commit::{commit, CommitStatement};
|
||||
|
@ -31,7 +33,7 @@ use nom::multi::many0;
|
|||
use nom::multi::separated_list1;
|
||||
use nom::sequence::delimited;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::fmt::{self, Display, Formatter, Write};
|
||||
use std::ops::Deref;
|
||||
use std::time::Duration;
|
||||
|
||||
|
@ -48,7 +50,9 @@ impl Deref for Statements {
|
|||
impl fmt::Display for Statements {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
Display::fmt(
|
||||
&self.0.iter().map(|ref v| format!("{};", v)).collect::<Vec<_>>().join("\n"),
|
||||
&Fmt::pretty_new_line_separated(
|
||||
self.0.iter().map(|v| Fmt::new(v, |v, f| write!(f, "{};", v))),
|
||||
),
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
@ -148,25 +152,25 @@ impl Statement {
|
|||
impl Display for Statement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Use(v) => Display::fmt(v, f),
|
||||
Self::Set(v) => Display::fmt(v, f),
|
||||
Self::Info(v) => Display::fmt(v, f),
|
||||
Self::Live(v) => Display::fmt(v, f),
|
||||
Self::Kill(v) => Display::fmt(v, f),
|
||||
Self::Begin(v) => Display::fmt(v, f),
|
||||
Self::Cancel(v) => Display::fmt(v, f),
|
||||
Self::Commit(v) => Display::fmt(v, f),
|
||||
Self::Output(v) => Display::fmt(v, f),
|
||||
Self::Ifelse(v) => Display::fmt(v, f),
|
||||
Self::Select(v) => Display::fmt(v, f),
|
||||
Self::Create(v) => Display::fmt(v, f),
|
||||
Self::Update(v) => Display::fmt(v, f),
|
||||
Self::Relate(v) => Display::fmt(v, f),
|
||||
Self::Delete(v) => Display::fmt(v, f),
|
||||
Self::Insert(v) => Display::fmt(v, f),
|
||||
Self::Define(v) => Display::fmt(v, f),
|
||||
Self::Remove(v) => Display::fmt(v, f),
|
||||
Self::Option(v) => Display::fmt(v, f),
|
||||
Self::Use(v) => write!(Pretty::from(f), "{}", v),
|
||||
Self::Set(v) => write!(Pretty::from(f), "{}", v),
|
||||
Self::Info(v) => write!(Pretty::from(f), "{}", v),
|
||||
Self::Live(v) => write!(Pretty::from(f), "{}", v),
|
||||
Self::Kill(v) => write!(Pretty::from(f), "{}", v),
|
||||
Self::Begin(v) => write!(Pretty::from(f), "{}", v),
|
||||
Self::Cancel(v) => write!(Pretty::from(f), "{}", v),
|
||||
Self::Commit(v) => write!(Pretty::from(f), "{}", v),
|
||||
Self::Output(v) => write!(Pretty::from(f), "{}", v),
|
||||
Self::Ifelse(v) => write!(Pretty::from(f), "{}", v),
|
||||
Self::Select(v) => write!(Pretty::from(f), "{}", v),
|
||||
Self::Create(v) => write!(Pretty::from(f), "{}", v),
|
||||
Self::Update(v) => write!(Pretty::from(f), "{}", v),
|
||||
Self::Relate(v) => write!(Pretty::from(f), "{}", v),
|
||||
Self::Delete(v) => write!(Pretty::from(f), "{}", v),
|
||||
Self::Insert(v) => write!(Pretty::from(f), "{}", v),
|
||||
Self::Define(v) => write!(Pretty::from(f), "{}", v),
|
||||
Self::Remove(v) => write!(Pretty::from(f), "{}", v),
|
||||
Self::Option(v) => write!(Pretty::from(f), "{}", v),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ use crate::sql::comment::shouldbespace;
|
|||
use crate::sql::duration::{duration, Duration};
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::escape::escape_str;
|
||||
use crate::sql::fmt::is_pretty;
|
||||
use crate::sql::fmt::pretty_indent;
|
||||
use crate::sql::ident::{ident, Ident};
|
||||
use crate::sql::idiom;
|
||||
use crate::sql::idiom::{Idiom, Idioms};
|
||||
|
@ -31,8 +33,7 @@ use rand::distributions::Alphanumeric;
|
|||
use rand::rngs::OsRng;
|
||||
use rand::Rng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::fmt::Display;
|
||||
use std::fmt::{self, Display, Write};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
pub enum DefineStatement {
|
||||
|
@ -709,19 +710,24 @@ impl fmt::Display for DefineTableStatement {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "DEFINE TABLE {}", self.name)?;
|
||||
if self.drop {
|
||||
write!(f, " DROP")?
|
||||
}
|
||||
if self.full {
|
||||
write!(f, " SCHEMAFULL")?
|
||||
}
|
||||
if !self.full {
|
||||
write!(f, " SCHEMALESS")?
|
||||
f.write_str(" DROP")?;
|
||||
}
|
||||
f.write_str(if self.full {
|
||||
" SCHEMAFULL"
|
||||
} else {
|
||||
" SCHEMALESS"
|
||||
})?;
|
||||
if let Some(ref v) = self.view {
|
||||
write!(f, " {}", v)?
|
||||
}
|
||||
if !self.permissions.is_full() {
|
||||
write!(f, " {}", self.permissions)?;
|
||||
let _indent = if is_pretty() {
|
||||
Some(pretty_indent())
|
||||
} else {
|
||||
f.write_char(' ')?;
|
||||
None
|
||||
};
|
||||
write!(f, "{}", self.permissions)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ use crate::dbs::Transaction;
|
|||
use crate::err::Error;
|
||||
use crate::sql::comment::shouldbespace;
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::fmt::{fmt_separated_by, Fmt};
|
||||
use crate::sql::value::{value, Value};
|
||||
use derive::Store;
|
||||
use nom::bytes::complete::tag_no_case;
|
||||
|
@ -11,6 +12,7 @@ use nom::combinator::opt;
|
|||
use nom::multi::separated_list0;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::fmt::Display;
|
||||
|
||||
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, Store, Hash)]
|
||||
pub struct IfelseStatement {
|
||||
|
@ -48,21 +50,21 @@ impl IfelseStatement {
|
|||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for IfelseStatement {
|
||||
impl Display for IfelseStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
Display::fmt(
|
||||
&Fmt::new(
|
||||
self.exprs.iter().map(|args| {
|
||||
Fmt::new(args, |(cond, then), f| write!(f, "IF {} THEN {}", cond, then))
|
||||
}),
|
||||
fmt_separated_by(" ELSE "),
|
||||
),
|
||||
f,
|
||||
"{}",
|
||||
self.exprs
|
||||
.iter()
|
||||
.map(|(ref cond, ref then)| format!("IF {} THEN {}", cond, then))
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ELSE ")
|
||||
)?;
|
||||
if let Some(ref v) = self.close {
|
||||
write!(f, " ELSE {}", v)?
|
||||
}
|
||||
write!(f, " END")?;
|
||||
f.write_str(" END")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ use crate::sql::duration::{duration, Duration};
|
|||
use crate::sql::edges::{edges, Edges};
|
||||
use crate::sql::error::IResult;
|
||||
use crate::sql::expression::{expression, Expression};
|
||||
use crate::sql::fmt::Fmt;
|
||||
use crate::sql::fmt::{Fmt, Pretty};
|
||||
use crate::sql::function::{function, Function};
|
||||
use crate::sql::future::{future, Future};
|
||||
use crate::sql::geometry::{geometry, Geometry};
|
||||
|
@ -49,7 +49,7 @@ use serde::{Deserialize, Serialize};
|
|||
use std::cmp::Ordering;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::fmt::{self, Display, Formatter, Write};
|
||||
use std::ops;
|
||||
use std::ops::Deref;
|
||||
use std::str::FromStr;
|
||||
|
@ -1284,6 +1284,7 @@ impl Value {
|
|||
|
||||
impl fmt::Display for Value {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut f = Pretty::from(f);
|
||||
match self {
|
||||
Value::None => write!(f, "NONE"),
|
||||
Value::Null => write!(f, "NULL"),
|
||||
|
|
Loading…
Reference in a new issue