Skip to content

Initial database schema #100

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ jobs:
toolchain: ${{ matrix.rust-version }}
override: true

- name: Install libpq (Windows)
if: matrix.os == 'windows-latest'
shell: bash
run: |
choco install postgresql12 --force --params '/Password:root'
echo '::add-path::C:\Program Files\PostgreSQL\12\bin'
echo '::add-path::C:\Program Files\PostgreSQL\12\lib'

- uses: actions-rs/cargo@v1
with:
command: test
Expand Down
133 changes: 119 additions & 14 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,7 @@ categories = [
publish = false

[dependencies]
chrono = "0.4.13"
diesel = { version = "1.4.5", features = ["postgres"] }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: Do we need to install diesiel-cli from master?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My current understanding is that this is not possible at the moment, because diesel_cli is a binary-only crate :( rust-lang/cargo#4316

Let me try using https://docs.rs/diesel_migrations/1.4.0/diesel_migrations/index.html in a follow up PR. Or just replace this with alembic ;)

rocket = "0.4.5"
rocket_contrib = {version = "0.4.5", features = ["json"]}
8 changes: 8 additions & 0 deletions diesel.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# For documentation on how to configure this file,
# see diesel.rs/guides/configuring-diesel-cli

[print_schema]
file = "src/storage/sql/schema.rs"

[migrations_directory]
dir = "src/storage/sql/migrations"
3 changes: 3 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@

#![feature(proc_macro_hygiene, decl_macro)]

#[macro_use]
extern crate diesel;
#[macro_use]
extern crate rocket;
#[macro_use]
extern crate rocket_contrib;

mod application;
mod routes;
mod storage;

fn main() {
let app = application::create_app();
Expand Down
1 change: 1 addition & 0 deletions src/storage/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod sql;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
DROP TABLE tags;
DROP TABLE changesets;
DROP TABLE snippets;
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
CREATE TABLE snippets (
-- an internal autoincrementing identifier used in foreign keys.
-- Normally not visible publicly, except for the case when it is
-- used for looking legacy snippets up by id
id SERIAL PRIMARY KEY,
-- a short unique snippet identifier visible to users
slug VARCHAR(32) NOT NULL,

title TEXT,
syntax TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,

-- slugs must be unique (this will also automatically create a unique index)
CONSTRAINT uq_slug UNIQUE (slug)
);


-- will be used for pagination; slug guarantees uniqueness of the sorting key
CREATE INDEX snippets_created_at_slug ON snippets (created_at, slug);
CREATE INDEX snippets_updated_at_slug ON snippets (updated_at, slug);


CREATE TABLE changesets (
id SERIAL PRIMARY KEY,
snippet_id INTEGER NOT NULL,

-- numeric index used to determine the ordering of changesets for a given snippet
version INTEGER DEFAULT 0 NOT NULL,
content TEXT NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,

-- there can be multiple changesets per snippet
CONSTRAINT fk_snippet FOREIGN KEY (snippet_id) REFERENCES snippets(id),
-- but each one is supposed to have a unique version number
CONSTRAINT uq_version UNIQUE (snippet_id, version),
-- sanity check: do not allow empty changesets
CONSTRAINT check_not_empty CHECK (LENGTH(content) > 0),
-- sanity check: version numbers are non-negative integers
CONSTRAINT check_non_negative_version CHECK (version >= 0)
);


-- tags could have been associated with snippets as M:M via an auxiliary table,
-- but Diesel only supports child-parent associations, so let's do that instead
CREATE TABLE tags (
id SERIAL PRIMARY KEY,
snippet_id INTEGER NOT NULL,

value TEXT NOT NULL,

-- there can be multiple tags per snippet
CONSTRAINT fk_snippet FOREIGN KEY (snippet_id) REFERENCES snippets(id),
-- do not allow to abuse the tags for storing too much data
CONSTRAINT check_length CHECK (LENGTH(value) < 128),
-- do not allow repeated tags per snippet
CONSTRAINT uq_snippet_tag UNIQUE (snippet_id, value)
);
1 change: 1 addition & 0 deletions src/storage/sql/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mod schema;
36 changes: 36 additions & 0 deletions src/storage/sql/schema.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// @generated automatically by Diesel CLI.

diesel::table! {
changesets (id) {
id -> Int4,
snippet_id -> Int4,
version -> Int4,
content -> Text,
created_at -> Timestamptz,
updated_at -> Timestamptz,
}
}

diesel::table! {
snippets (id) {
id -> Int4,
slug -> Varchar,
title -> Nullable<Text>,
syntax -> Nullable<Text>,
created_at -> Timestamptz,
updated_at -> Timestamptz,
}
}

diesel::table! {
tags (id) {
id -> Int4,
snippet_id -> Int4,
value -> Text,
}
}

diesel::joinable!(changesets -> snippets (snippet_id));
diesel::joinable!(tags -> snippets (snippet_id));

diesel::allow_tables_to_appear_in_same_query!(changesets, snippets, tags,);