Use custom types over text in database

This commit is contained in:
Adrian Woźniak 2020-04-01 13:29:43 +02:00
parent 5758c79f35
commit 4a9ba8e2a3
18 changed files with 469 additions and 74 deletions

1
Cargo.lock generated
View File

@ -1055,6 +1055,7 @@ name = "jirs-data"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"chrono", "chrono",
"diesel",
"serde", "serde",
"serde_json", "serde_json",
"uuid 0.8.1", "uuid 0.8.1",

View File

@ -30,14 +30,12 @@
} }
.modal > .clickableOverlay > .styledModal.center { .modal > .clickableOverlay > .styledModal.center {
/*max-width: ${props => props.width}px;*/
vertical-align: middle; vertical-align: middle;
border-radius: 3px; border-radius: 3px;
box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.1); box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.1);
} }
.modal > .clickableOverlay > .styledModal.aside { .modal > .clickableOverlay > .styledModal.aside {
/*max-width: ${props => props.width}px;*/
min-height: 100vh; min-height: 100vh;
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.15); box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.15);
} }

View File

@ -106,6 +106,7 @@ impl Default for Model {
} }
} }
#[allow(dead_code)]
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub enum Icon { pub enum Icon {
Bug, Bug,

View File

@ -1,6 +1,6 @@
use seed::{prelude::*, *}; use seed::{prelude::*, *};
use jirs_data::{FullProject, Issue, IssuePriority, IssueType, UpdateIssuePayload}; use jirs_data::*;
use crate::model::{Icon, Model, Page}; use crate::model::{Icon, Model, Page};
use crate::shared::styled_avatar::StyledAvatar; use crate::shared::styled_avatar::StyledAvatar;
@ -251,8 +251,6 @@ fn avatars_filters(model: &Model) -> Node<Msg> {
} }
fn project_board_lists(model: &Model) -> Node<Msg> { fn project_board_lists(model: &Model) -> Node<Msg> {
use jirs_data::IssueStatus;
div![ div![
id!["projectBoardLists"], id!["projectBoardLists"],
project_issue_list(model, IssueStatus::Backlog), project_issue_list(model, IssueStatus::Backlog),
@ -317,28 +315,25 @@ fn project_issue(model: &Model, project: &FullProject, issue: &Issue) -> Node<Ms
}) })
.collect(); .collect();
let issue_type_icon = match issue.issue_type.parse::<IssueType>() { let issue_type_icon = {
Ok(icon) => { let mut node = crate::shared::styled_icon(issue.issue_type.clone().into());
let mut node = crate::shared::styled_icon(icon.into());
node.add_style( node.add_style(
St::Color, St::Color,
format!("var(--{issue_type})", issue_type = issue.issue_type), format!(
"var(--{issue_type})",
issue_type = issue.issue_type.to_string()
),
); );
node node
}
Err(e) => span![format!("{}", e)],
}; };
let priority_icon = match issue.priority.parse::<IssuePriority>() { let priority_icon = {
Ok(p) => { let icon = match issue.priority {
let icon = match p {
IssuePriority::Low | IssuePriority::Lowest => Icon::ArrowDown, IssuePriority::Low | IssuePriority::Lowest => Icon::ArrowDown,
_ => Icon::ArrowUp, _ => Icon::ArrowUp,
}; };
let mut node = crate::shared::styled_icon(icon); let mut node = crate::shared::styled_icon(icon);
node.add_style(St::Color, format!("var(--{})", p.to_lower_name())); node.add_style(St::Color, format!("var(--{})", issue.priority));
node node
}
Err(e) => span![e.clone()],
}; };
let issue_id = issue.id; let issue_id = issue.id;

View File

@ -1,4 +1,4 @@
use seed::{prelude::*, *}; use seed::prelude::*;
use crate::shared::inner_layout; use crate::shared::inner_layout;
use crate::{model, Msg}; use crate::{model, Msg};

View File

@ -4,6 +4,7 @@ use crate::model::Icon;
use crate::shared::{styled_icon, ToNode}; use crate::shared::{styled_icon, ToNode};
use crate::Msg; use crate::Msg;
#[allow(dead_code)]
#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)] #[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]
pub enum Variant { pub enum Variant {
Center, Center,
@ -54,12 +55,16 @@ pub fn render(values: Modal) -> Node<Msg> {
} else { } else {
empty![] empty![]
}; };
let clickable_class = format!("clickableOverlay {}", variant.to_class_name());
let styled_modal_class = format!("styledModal {}", variant.to_class_name());
let styled_modal_style = format!("max-width: {width}px", width = width);
div![ div![
attrs![At::Class => "modal"], attrs![At::Class => "modal"],
div![ div![
attrs![At::Class => format!("clickableOverlay {}", variant.to_class_name())], attrs![At::Class => clickable_class],
div![ div![
attrs![At::Class => format!("styledModal {}", variant.to_class_name())], attrs![At::Class => styled_modal_class, At::Style => styled_modal_style],
icon, icon,
children children
] ]

View File

@ -4,6 +4,7 @@ use crate::model::Icon;
use crate::shared::{styled_icon, ToNode}; use crate::shared::{styled_icon, ToNode};
use crate::Msg; use crate::Msg;
#[allow(dead_code)]
pub enum Variant { pub enum Variant {
Primary, Primary,
Success, Success,

View File

@ -12,10 +12,16 @@ license = "MPL-2.0"
name = "jirs_data" name = "jirs_data"
path = "./src/lib.rs" path = "./src/lib.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features]
backend = [ "diesel" ]
[dependencies] [dependencies]
serde = "*" serde = "*"
serde_json = "*" serde_json = "*"
chrono = { version = "*", features = [ "serde" ] } chrono = { version = "*", features = [ "serde" ] }
uuid = { version = ">=0.7.0, <0.9.0", features = ["serde"] } uuid = { version = ">=0.7.0, <0.9.0", features = ["serde"] }
[dependencies.diesel]
optional = true
version = "1.4.4"
features = [ "unstable", "postgres", "numeric", "extras", "uuidv07" ]

View File

@ -1,15 +1,25 @@
use std::str::FromStr; use std::str::FromStr;
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
#[cfg(feature = "backend")]
use diesel::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use uuid::Uuid; use uuid::Uuid;
#[cfg(feature = "backend")]
pub use sql::*;
#[cfg(feature = "backend")]
pub mod sql;
pub trait ResponseData { pub trait ResponseData {
type Response: Serialize; type Response: Serialize;
fn into_response(self) -> Self::Response; fn into_response(self) -> Self::Response;
} }
#[cfg_attr(feature = "backend", derive(FromSqlRow, AsExpression))]
#[cfg_attr(feature = "backend", sql_type = "IssueTypeType")]
#[derive(Clone, Deserialize, Serialize, Debug, PartialOrd, PartialEq)] #[derive(Clone, Deserialize, Serialize, Debug, PartialOrd, PartialEq)]
#[serde(rename_all = "lowercase")] #[serde(rename_all = "lowercase")]
pub enum IssueType { pub enum IssueType {
@ -31,14 +41,13 @@ impl FromStr for IssueType {
} }
} }
impl ToString for IssueType { impl std::fmt::Display for IssueType {
fn to_string(&self) -> String { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
IssueType::Task => "Task", IssueType::Task => f.write_str("task"),
IssueType::Bug => "Bug", IssueType::Bug => f.write_str("bug"),
IssueType::Story => "Story", IssueType::Story => f.write_str("story"),
} }
.to_string()
} }
} }
@ -88,6 +97,8 @@ impl IssueStatus {
} }
} }
#[cfg_attr(feature = "backend", derive(FromSqlRow, AsExpression))]
#[cfg_attr(feature = "backend", sql_type = "IssuePriorityType")]
#[derive(Clone, Deserialize, Serialize, Debug, PartialOrd, PartialEq)] #[derive(Clone, Deserialize, Serialize, Debug, PartialOrd, PartialEq)]
pub enum IssuePriority { pub enum IssuePriority {
Highest, Highest,
@ -112,6 +123,18 @@ impl FromStr for IssuePriority {
} }
} }
impl std::fmt::Display for IssuePriority {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
IssuePriority::Highest => f.write_str("highest"),
IssuePriority::High => f.write_str("high"),
IssuePriority::Medium => f.write_str("medium"),
IssuePriority::Low => f.write_str("low"),
IssuePriority::Lowest => f.write_str("lowest"),
}
}
}
impl IssuePriority { impl IssuePriority {
pub fn to_text_value(&self) -> &str { pub fn to_text_value(&self) -> &str {
match self { match self {
@ -123,16 +146,6 @@ impl IssuePriority {
} }
} }
pub fn to_lower_name(&self) -> &str {
match self {
IssuePriority::Highest => "highest",
IssuePriority::High => "high",
IssuePriority::Medium => "medium",
IssuePriority::Low => "low",
IssuePriority::Lowest => "lowest",
}
}
pub fn to_value(&self) -> i32 { pub fn to_value(&self) -> i32 {
match self { match self {
IssuePriority::Highest => 5, IssuePriority::Highest => 5,
@ -185,9 +198,9 @@ pub struct FullIssue {
pub id: i32, pub id: i32,
pub title: String, pub title: String,
#[serde(rename = "type")] #[serde(rename = "type")]
pub issue_type: String, pub issue_type: IssueType,
pub status: String, pub status: String,
pub priority: String, pub priority: IssuePriority,
pub list_position: f64, pub list_position: f64,
pub description: Option<String>, pub description: Option<String>,
pub description_text: Option<String>, pub description_text: Option<String>,
@ -235,9 +248,9 @@ pub struct Issue {
pub id: i32, pub id: i32,
pub title: String, pub title: String,
#[serde(rename = "type")] #[serde(rename = "type")]
pub issue_type: String, pub issue_type: IssueType,
pub status: IssueStatus, pub status: IssueStatus,
pub priority: String, pub priority: IssuePriority,
pub list_position: f64, pub list_position: f64,
pub description: Option<String>, pub description: Option<String>,
pub description_text: Option<String>, pub description_text: Option<String>,
@ -293,9 +306,9 @@ pub struct Token {
pub struct UpdateIssuePayload { pub struct UpdateIssuePayload {
pub title: Option<String>, pub title: Option<String>,
#[serde(rename = "type")] #[serde(rename = "type")]
pub issue_type: Option<String>, pub issue_type: Option<IssueType>,
pub status: Option<String>, pub status: Option<String>,
pub priority: Option<String>, pub priority: Option<IssuePriority>,
pub list_position: Option<f64>, pub list_position: Option<f64>,
pub description: Option<Option<String>>, pub description: Option<Option<String>>,
pub description_text: Option<Option<String>>, pub description_text: Option<Option<String>>,
@ -327,9 +340,9 @@ pub struct UpdateCommentPayload {
pub struct CreateIssuePayload { pub struct CreateIssuePayload {
pub title: String, pub title: String,
#[serde(rename = "type")] #[serde(rename = "type")]
pub issue_type: String, pub issue_type: IssueType,
pub status: String, pub status: String,
pub priority: String, pub priority: IssuePriority,
pub description: Option<String>, pub description: Option<String>,
pub description_text: Option<String>, pub description_text: Option<String>,
pub estimate: Option<i32>, pub estimate: Option<i32>,

81
jirs-data/src/sql.rs Normal file
View File

@ -0,0 +1,81 @@
use std::io::Write;
use diesel::{deserialize::*, pg::*, serialize::*, *};
use crate::{IssuePriority, IssueType};
#[derive(SqlType)]
#[postgres(type_name = "IssuePriorityType")]
pub struct IssuePriorityType;
impl ToSql<IssuePriorityType, Pg> for IssuePriority {
fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
match *self {
IssuePriority::Highest => out.write_all(b"highest")?,
IssuePriority::High => out.write_all(b"high")?,
IssuePriority::Medium => out.write_all(b"medium")?,
IssuePriority::Low => out.write_all(b"low")?,
IssuePriority::Lowest => out.write_all(b"lowest")?,
}
Ok(IsNull::No)
}
}
fn issue_priority_from_sql(bytes: Option<&[u8]>) -> deserialize::Result<IssuePriority> {
match not_none!(bytes) {
b"5" | b"highest" => Ok(IssuePriority::Highest),
b"4" | b"high" => Ok(IssuePriority::High),
b"3" | b"medium" => Ok(IssuePriority::Medium),
b"2" | b"low" => Ok(IssuePriority::Low),
b"1" | b"lowest" => Ok(IssuePriority::Lowest),
_ => Ok(IssuePriority::Lowest),
}
}
impl FromSql<IssuePriorityType, Pg> for IssuePriority {
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
issue_priority_from_sql(bytes)
}
}
impl FromSql<sql_types::Text, Pg> for IssuePriority {
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
issue_priority_from_sql(bytes)
}
}
#[derive(SqlType)]
#[postgres(type_name = "IssueTypeType")]
pub struct IssueTypeType;
fn issue_type_from_sql(bytes: Option<&[u8]>) -> deserialize::Result<IssueType> {
match not_none!(bytes) {
b"task" => Ok(IssueType::Task),
b"bug" => Ok(IssueType::Bug),
b"story" => Ok(IssueType::Story),
_ => Ok(IssueType::Task),
}
}
impl FromSql<IssueTypeType, Pg> for IssueType {
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
issue_type_from_sql(bytes)
}
}
impl FromSql<sql_types::Text, Pg> for IssueType {
fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
issue_type_from_sql(bytes)
}
}
impl ToSql<IssueTypeType, Pg> for IssueType {
fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
match *self {
IssueType::Task => out.write_all(b"task")?,
IssueType::Story => out.write_all(b"story")?,
IssueType::Bug => out.write_all(b"bug")?,
}
Ok(IsNull::No)
}
}

View File

@ -13,7 +13,6 @@ name = "jirs_server"
path = "./src/main.rs" path = "./src/main.rs"
[dependencies] [dependencies]
jirs-data = { path = "../jirs-data" }
serde = { version = "*", features = ["derive"] } serde = { version = "*", features = ["derive"] }
actix = { version = "*" } actix = { version = "*" }
actix-web = { version = "*" } actix-web = { version = "*" }
@ -45,3 +44,6 @@ futures = { version = "*" }
version = "1.4.4" version = "1.4.4"
features = [ "unstable", "postgres", "numeric", "extras", "uuidv07" ] features = [ "unstable", "postgres", "numeric", "extras", "uuidv07" ]
[dependencies.jirs-data]
path = "../jirs-data"
features = [ "backend" ]

View File

@ -3,4 +3,5 @@
[print_schema] [print_schema]
file = "src/schema.rs" file = "src/schema.rs"
import_types = ["diesel::sql_types::*", "jirs_data::sql::*"]
with_docs = true

View File

@ -1,4 +1,6 @@
DROP TYPE IF EXISTS ProjectCategory CASCADE; DROP TYPE IF EXISTS "ProjectCategoryType" CASCADE;
DROP TYPE IF EXISTS "IssuePriorityType" CASCADE;
DROP TYPE IF EXISTS "IssueTypeType" CASCADE;
DROP TABLE IF EXISTS projects CASCADE; DROP TABLE IF EXISTS projects CASCADE;

View File

@ -1,11 +1,25 @@
CREATE EXTENSION "uuid-ossp"; CREATE EXTENSION "uuid-ossp";
CREATE TYPE ProjectCategory as ENUM ( CREATE TYPE "ProjectCategoryType" as ENUM (
'software', 'software',
'marketing', 'marketing',
'business' 'business'
); );
CREATE TYPE "IssuePriorityType" as ENUM (
'highest',
'high',
'medium',
'low',
'lowest'
);
CREATE TYPE "IssueTypeType" AS ENUM (
'task',
'bug',
'story'
);
CREATE TABLE projects ( CREATE TABLE projects (
id serial primary key not null, id serial primary key not null,
name text not null, name text not null,
@ -29,9 +43,9 @@ CREATE TABLE users (
CREATE TABLE issues ( CREATE TABLE issues (
id serial primary key not null, id serial primary key not null,
title text not null, title text not null,
issue_type text not null, issue_type "IssueTypeType" not null,
status text not null, status text not null,
priority text not null, priority "IssuePriorityType" not null,
list_position double precision not null default 0, list_position double precision not null default 0,
description text, description text,
description_text text, description_text text,
@ -61,4 +75,3 @@ CREATE TABLE tokens (
created_at timestamp not null default now(), created_at timestamp not null default now(),
updated_at timestamp not null default now() updated_at timestamp not null default now()
); );

View File

@ -34,7 +34,7 @@ insert into issues(
), ( ), (
'Foo3', 'Foo3',
'bug', 'bug',
'inprogress', 'in_progress',
'low', 'low',
3, 3,
'hello world 3', 'hello world 3',

View File

@ -4,6 +4,8 @@ use diesel::expression::sql_literal::sql;
use diesel::prelude::*; use diesel::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use jirs_data::{IssuePriority, IssueType};
use crate::db::DbExecutor; use crate::db::DbExecutor;
use crate::errors::ServiceErrors; use crate::errors::ServiceErrors;
use crate::models::Issue; use crate::models::Issue;
@ -66,9 +68,9 @@ impl Handler<LoadProjectIssues> for DbExecutor {
pub struct UpdateIssue { pub struct UpdateIssue {
pub issue_id: i32, pub issue_id: i32,
pub title: Option<String>, pub title: Option<String>,
pub issue_type: Option<String>, pub issue_type: Option<IssueType>,
pub status: Option<String>, pub status: Option<String>,
pub priority: Option<String>, pub priority: Option<IssuePriority>,
pub list_position: Option<f64>, pub list_position: Option<f64>,
pub description: Option<Option<String>>, pub description: Option<Option<String>>,
pub description_text: Option<Option<String>>, pub description_text: Option<Option<String>>,
@ -191,9 +193,9 @@ impl Handler<DeleteIssue> for DbExecutor {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct CreateIssue { pub struct CreateIssue {
pub title: String, pub title: String,
pub issue_type: String, pub issue_type: IssueType,
pub status: String, pub status: String,
pub priority: String, pub priority: IssuePriority,
pub description: Option<String>, pub description: Option<String>,
pub description_text: Option<String>, pub description_text: Option<String>,
pub estimate: Option<i32>, pub estimate: Option<i32>,

View File

@ -2,7 +2,8 @@ use chrono::NaiveDateTime;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use uuid::Uuid; use uuid::Uuid;
use jirs_data::IssueStatus; use jirs_data::sql::*;
use jirs_data::{IssuePriority, IssueStatus, IssueType};
use crate::schema::*; use crate::schema::*;
@ -47,9 +48,9 @@ pub struct Issue {
pub id: i32, pub id: i32,
pub title: String, pub title: String,
#[serde(rename = "type")] #[serde(rename = "type")]
pub issue_type: String, pub issue_type: IssueType,
pub status: String, pub status: String,
pub priority: String, pub priority: IssuePriority,
pub list_position: f64, pub list_position: f64,
pub description: Option<String>, pub description: Option<String>,
pub description_text: Option<String>, pub description_text: Option<String>,
@ -121,9 +122,9 @@ impl Into<jirs_data::FullIssue> for Issue {
pub struct CreateIssueForm { pub struct CreateIssueForm {
pub title: String, pub title: String,
#[serde(rename = "type")] #[serde(rename = "type")]
pub issue_type: String, pub issue_type: IssueType,
pub status: String, pub status: String,
pub priority: String, pub priority: IssuePriority,
pub list_position: f64, pub list_position: f64,
pub description: Option<String>, pub description: Option<String>,
pub description_text: Option<String>, pub description_text: Option<String>,

View File

@ -1,75 +1,341 @@
table! { table! {
use diesel::sql_types::*;
use jirs_data::sql::*;
/// Representation of the `comments` table.
///
/// (Automatically generated by Diesel.)
comments (id) { comments (id) {
/// The `id` column of the `comments` table.
///
/// Its SQL type is `Int4`.
///
/// (Automatically generated by Diesel.)
id -> Int4, id -> Int4,
/// The `body` column of the `comments` table.
///
/// Its SQL type is `Text`.
///
/// (Automatically generated by Diesel.)
body -> Text, body -> Text,
/// The `user_id` column of the `comments` table.
///
/// Its SQL type is `Int4`.
///
/// (Automatically generated by Diesel.)
user_id -> Int4, user_id -> Int4,
/// The `issue_id` column of the `comments` table.
///
/// Its SQL type is `Int4`.
///
/// (Automatically generated by Diesel.)
issue_id -> Int4, issue_id -> Int4,
/// The `created_at` column of the `comments` table.
///
/// Its SQL type is `Timestamp`.
///
/// (Automatically generated by Diesel.)
created_at -> Timestamp, created_at -> Timestamp,
/// The `updated_at` column of the `comments` table.
///
/// Its SQL type is `Timestamp`.
///
/// (Automatically generated by Diesel.)
updated_at -> Timestamp, updated_at -> Timestamp,
} }
} }
table! { table! {
use diesel::sql_types::*;
use jirs_data::sql::*;
/// Representation of the `issue_assignees` table.
///
/// (Automatically generated by Diesel.)
issue_assignees (id) { issue_assignees (id) {
/// The `id` column of the `issue_assignees` table.
///
/// Its SQL type is `Int4`.
///
/// (Automatically generated by Diesel.)
id -> Int4, id -> Int4,
/// The `issue_id` column of the `issue_assignees` table.
///
/// Its SQL type is `Int4`.
///
/// (Automatically generated by Diesel.)
issue_id -> Int4, issue_id -> Int4,
/// The `user_id` column of the `issue_assignees` table.
///
/// Its SQL type is `Int4`.
///
/// (Automatically generated by Diesel.)
user_id -> Int4, user_id -> Int4,
/// The `created_at` column of the `issue_assignees` table.
///
/// Its SQL type is `Timestamp`.
///
/// (Automatically generated by Diesel.)
created_at -> Timestamp, created_at -> Timestamp,
/// The `updated_at` column of the `issue_assignees` table.
///
/// Its SQL type is `Timestamp`.
///
/// (Automatically generated by Diesel.)
updated_at -> Timestamp, updated_at -> Timestamp,
} }
} }
table! { table! {
use diesel::sql_types::*;
use jirs_data::sql::*;
/// Representation of the `issues` table.
///
/// (Automatically generated by Diesel.)
issues (id) { issues (id) {
/// The `id` column of the `issues` table.
///
/// Its SQL type is `Int4`.
///
/// (Automatically generated by Diesel.)
id -> Int4, id -> Int4,
/// The `title` column of the `issues` table.
///
/// Its SQL type is `Text`.
///
/// (Automatically generated by Diesel.)
title -> Text, title -> Text,
issue_type -> Text, /// The `issue_type` column of the `issues` table.
///
/// Its SQL type is `IssueTypeType`.
///
/// (Automatically generated by Diesel.)
issue_type -> IssueTypeType,
/// The `status` column of the `issues` table.
///
/// Its SQL type is `Text`.
///
/// (Automatically generated by Diesel.)
status -> Text, status -> Text,
priority -> Text, /// The `priority` column of the `issues` table.
///
/// Its SQL type is `IssuePriorityType`.
///
/// (Automatically generated by Diesel.)
priority -> IssuePriorityType,
/// The `list_position` column of the `issues` table.
///
/// Its SQL type is `Float8`.
///
/// (Automatically generated by Diesel.)
list_position -> Float8, list_position -> Float8,
/// The `description` column of the `issues` table.
///
/// Its SQL type is `Nullable<Text>`.
///
/// (Automatically generated by Diesel.)
description -> Nullable<Text>, description -> Nullable<Text>,
/// The `description_text` column of the `issues` table.
///
/// Its SQL type is `Nullable<Text>`.
///
/// (Automatically generated by Diesel.)
description_text -> Nullable<Text>, description_text -> Nullable<Text>,
/// The `estimate` column of the `issues` table.
///
/// Its SQL type is `Nullable<Int4>`.
///
/// (Automatically generated by Diesel.)
estimate -> Nullable<Int4>, estimate -> Nullable<Int4>,
/// The `time_spent` column of the `issues` table.
///
/// Its SQL type is `Nullable<Int4>`.
///
/// (Automatically generated by Diesel.)
time_spent -> Nullable<Int4>, time_spent -> Nullable<Int4>,
/// The `time_remaining` column of the `issues` table.
///
/// Its SQL type is `Nullable<Int4>`.
///
/// (Automatically generated by Diesel.)
time_remaining -> Nullable<Int4>, time_remaining -> Nullable<Int4>,
/// The `reporter_id` column of the `issues` table.
///
/// Its SQL type is `Int4`.
///
/// (Automatically generated by Diesel.)
reporter_id -> Int4, reporter_id -> Int4,
/// The `project_id` column of the `issues` table.
///
/// Its SQL type is `Int4`.
///
/// (Automatically generated by Diesel.)
project_id -> Int4, project_id -> Int4,
/// The `created_at` column of the `issues` table.
///
/// Its SQL type is `Timestamp`.
///
/// (Automatically generated by Diesel.)
created_at -> Timestamp, created_at -> Timestamp,
/// The `updated_at` column of the `issues` table.
///
/// Its SQL type is `Timestamp`.
///
/// (Automatically generated by Diesel.)
updated_at -> Timestamp, updated_at -> Timestamp,
} }
} }
table! { table! {
use diesel::sql_types::*;
use jirs_data::sql::*;
/// Representation of the `projects` table.
///
/// (Automatically generated by Diesel.)
projects (id) { projects (id) {
/// The `id` column of the `projects` table.
///
/// Its SQL type is `Int4`.
///
/// (Automatically generated by Diesel.)
id -> Int4, id -> Int4,
/// The `name` column of the `projects` table.
///
/// Its SQL type is `Text`.
///
/// (Automatically generated by Diesel.)
name -> Text, name -> Text,
/// The `url` column of the `projects` table.
///
/// Its SQL type is `Text`.
///
/// (Automatically generated by Diesel.)
url -> Text, url -> Text,
/// The `description` column of the `projects` table.
///
/// Its SQL type is `Text`.
///
/// (Automatically generated by Diesel.)
description -> Text, description -> Text,
/// The `category` column of the `projects` table.
///
/// Its SQL type is `Text`.
///
/// (Automatically generated by Diesel.)
category -> Text, category -> Text,
/// The `created_at` column of the `projects` table.
///
/// Its SQL type is `Timestamp`.
///
/// (Automatically generated by Diesel.)
created_at -> Timestamp, created_at -> Timestamp,
/// The `updated_at` column of the `projects` table.
///
/// Its SQL type is `Timestamp`.
///
/// (Automatically generated by Diesel.)
updated_at -> Timestamp, updated_at -> Timestamp,
} }
} }
table! { table! {
use diesel::sql_types::*;
use jirs_data::sql::*;
/// Representation of the `tokens` table.
///
/// (Automatically generated by Diesel.)
tokens (id) { tokens (id) {
/// The `id` column of the `tokens` table.
///
/// Its SQL type is `Int4`.
///
/// (Automatically generated by Diesel.)
id -> Int4, id -> Int4,
/// The `user_id` column of the `tokens` table.
///
/// Its SQL type is `Int4`.
///
/// (Automatically generated by Diesel.)
user_id -> Int4, user_id -> Int4,
/// The `access_token` column of the `tokens` table.
///
/// Its SQL type is `Uuid`.
///
/// (Automatically generated by Diesel.)
access_token -> Uuid, access_token -> Uuid,
/// The `refresh_token` column of the `tokens` table.
///
/// Its SQL type is `Uuid`.
///
/// (Automatically generated by Diesel.)
refresh_token -> Uuid, refresh_token -> Uuid,
/// The `created_at` column of the `tokens` table.
///
/// Its SQL type is `Timestamp`.
///
/// (Automatically generated by Diesel.)
created_at -> Timestamp, created_at -> Timestamp,
/// The `updated_at` column of the `tokens` table.
///
/// Its SQL type is `Timestamp`.
///
/// (Automatically generated by Diesel.)
updated_at -> Timestamp, updated_at -> Timestamp,
} }
} }
table! { table! {
use diesel::sql_types::*;
use jirs_data::sql::*;
/// Representation of the `users` table.
///
/// (Automatically generated by Diesel.)
users (id) { users (id) {
/// The `id` column of the `users` table.
///
/// Its SQL type is `Int4`.
///
/// (Automatically generated by Diesel.)
id -> Int4, id -> Int4,
/// The `name` column of the `users` table.
///
/// Its SQL type is `Text`.
///
/// (Automatically generated by Diesel.)
name -> Text, name -> Text,
/// The `email` column of the `users` table.
///
/// Its SQL type is `Text`.
///
/// (Automatically generated by Diesel.)
email -> Text, email -> Text,
/// The `avatar_url` column of the `users` table.
///
/// Its SQL type is `Nullable<Text>`.
///
/// (Automatically generated by Diesel.)
avatar_url -> Nullable<Text>, avatar_url -> Nullable<Text>,
/// The `project_id` column of the `users` table.
///
/// Its SQL type is `Int4`.
///
/// (Automatically generated by Diesel.)
project_id -> Int4, project_id -> Int4,
/// The `created_at` column of the `users` table.
///
/// Its SQL type is `Timestamp`.
///
/// (Automatically generated by Diesel.)
created_at -> Timestamp, created_at -> Timestamp,
/// The `updated_at` column of the `users` table.
///
/// Its SQL type is `Timestamp`.
///
/// (Automatically generated by Diesel.)
updated_at -> Timestamp, updated_at -> Timestamp,
} }
} }
@ -83,4 +349,11 @@ joinable!(issues -> users (reporter_id));
joinable!(tokens -> users (user_id)); joinable!(tokens -> users (user_id));
joinable!(users -> projects (project_id)); joinable!(users -> projects (project_id));
allow_tables_to_appear_in_same_query!(comments, issue_assignees, issues, projects, tokens, users,); allow_tables_to_appear_in_same_query!(
comments,
issue_assignees,
issues,
projects,
tokens,
users,
);