Use fmt::Display trait for writing dbscheme

This commit is contained in:
Nick Rolfe
2020-10-21 12:45:54 +01:00
parent a7a18b8b0f
commit 5e3544fcc3
2 changed files with 80 additions and 62 deletions

View File

@@ -1,10 +1,12 @@
use std::fmt;
/// Represents a distinct entry in the database schema.
pub enum Entry {
/// An entry defining a database table.
Table(Table),
/// An entry defining type that is a union of other types.
Union { name: String, members: Vec<String> },
Union(Union),
}
/// A table in the database schema.
@@ -14,6 +16,12 @@ pub struct Table {
pub keysets: Option<Vec<String>>,
}
/// A union in the database schema.
pub struct Union {
pub name: String,
pub members: Vec<String>,
}
/// A column in a table.
pub struct Column {
pub db_type: DbColumnType,
@@ -101,6 +109,69 @@ pub fn escape_name(name: &str) -> String {
result
}
impl fmt::Display for Table {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for keyset in &self.keysets {
write!(f, "#keyset[")?;
for (key_index, key) in keyset.iter().enumerate() {
if key_index > 0 {
write!(f, ", ")?;
}
write!(f, "{}", key)?;
}
write!(f, "]\n")?;
}
write!(f, "{}(\n", self.name)?;
for (column_index, column) in self.columns.iter().enumerate() {
write!(f, " ")?;
if column.unique {
write!(f, "unique ")?;
}
write!(
f,
"{} ",
match column.db_type {
DbColumnType::Int => "int",
DbColumnType::String => "string",
}
)?;
write!(f, "{}: ", column.name)?;
match &column.ql_type {
QlColumnType::Int => write!(f, "int")?,
QlColumnType::String => write!(f, "string")?,
QlColumnType::Custom(name) => write!(f, "@{}", name)?,
}
if column.ql_type_is_ref {
write!(f, " ref")?;
}
if column_index + 1 != self.columns.len() {
write!(f, ",")?;
}
write!(f, "\n")?;
}
write!(f, ");")?;
Ok(())
}
}
impl fmt::Display for Union {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "@{} = ", self.name)?;
let mut first = true;
for member in &self.members {
if first {
first = false;
} else {
write!(f, " | ")?;
}
write!(f, "@{}", member)?;
}
Ok(())
}
}
/// Generates the dbscheme by writing the given dbscheme `entries` to the `file`.
pub fn write(
language_name: &str,
@@ -115,61 +186,8 @@ pub fn write(
for entry in entries {
match entry {
Entry::Table(table) => {
for keyset in &table.keysets {
write!(file, "#keyset[")?;
for (key_index, key) in keyset.iter().enumerate() {
if key_index > 0 {
write!(file, ", ")?;
}
write!(file, "{}", key)?;
}
write!(file, "]\n")?;
}
write!(file, "{}(\n", table.name)?;
for (column_index, column) in table.columns.iter().enumerate() {
write!(file, " ")?;
if column.unique {
write!(file, "unique ")?;
}
write!(
file,
"{} ",
match column.db_type {
DbColumnType::Int => "int",
DbColumnType::String => "string",
}
)?;
write!(file, "{}: ", column.name)?;
match &column.ql_type {
QlColumnType::Int => write!(file, "int")?,
QlColumnType::String => write!(file, "string")?,
QlColumnType::Custom(name) => write!(file, "@{}", name)?,
}
if column.ql_type_is_ref {
write!(file, " ref")?;
}
if column_index + 1 != table.columns.len() {
write!(file, ",")?;
}
write!(file, "\n")?;
}
write!(file, ");\n\n")?;
}
Entry::Union { name, members } => {
write!(file, "@{} = ", name)?;
let mut first = true;
for member in members {
if first {
first = false;
} else {
write!(file, " | ")?;
}
write!(file, "@{}", member)?;
}
write!(file, "\n\n")?;
}
Entry::Table(table) => write!(file, "{}\n\n", table)?,
Entry::Union(union) => write!(file, "{}\n\n", union)?,
}
}

View File

@@ -57,10 +57,10 @@ fn make_field_type(
field_type.named,
)));
}
entries.push(dbscheme::Entry::Union {
entries.push(dbscheme::Entry::Union(dbscheme::Union {
name: field_union_name.clone(),
members,
});
}));
field_union_name
}
}
@@ -144,10 +144,10 @@ fn convert_nodes(nodes: &[NodeInfo]) -> Vec<dbscheme::Entry> {
subtype.named,
)))
}
entries.push(dbscheme::Entry::Union {
entries.push(dbscheme::Entry::Union(dbscheme::Union {
name: dbscheme::escape_name(&node_type_name(&node.kind, node.named)),
members,
});
}));
} else {
// It's a product type, defined by a table.
let name = node_type_name(&node.kind, node.named);
@@ -207,10 +207,10 @@ fn convert_nodes(nodes: &[NodeInfo]) -> Vec<dbscheme::Entry> {
}
// Create a union of all database types.
entries.push(dbscheme::Entry::Union {
entries.push(dbscheme::Entry::Union(dbscheme::Union {
name: "top".to_string(),
members: top_members,
});
}));
entries
}