Initial commit

This commit is contained in:
Tobias Eidelpes 2022-11-02 09:40:49 +01:00
commit 3fc73fa6ac
7 changed files with 194 additions and 0 deletions

1
.env Normal file
View File

@ -0,0 +1 @@
DATABASE_URL=/tmp/pos.sqlite

11
.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
/target
/Cargo.lock
*~
\#*\#
/.emacs.desktop
/.emacs.desktop.lock
*.elc
auto-save-list
tramp
.\#*

17
Cargo.toml Normal file
View File

@ -0,0 +1,17 @@
[package]
name = "pos"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tide = "0.16.0"
async-std = { version = "1.12.0", features = ["attributes"] }
sqlx = { version = "0.6.2", features = ["runtime-async-std-native-tls", "chrono", "json", "sqlite"] }
dotenv = "0.15.0"
chrono = "0.4"
serde_json = "1.0"
anyhow = "1.0.65"
serde = { version = "1.0.145", features = ["derive"] }
pretty_env_logger = "0.4.0"

5
migrations/down.sql Normal file
View File

@ -0,0 +1,5 @@
-- This file should undo anything in `up.sql`
DROP TABLE products;
DROP TABLE orders_products;
DROP TABLE orders;
DROP VIEW totals_per_owner_and_order;

56
migrations/up.sql Normal file
View File

@ -0,0 +1,56 @@
-- Your SQL goes here
CREATE TABLE products (
id INTEGER PRIMARY KEY NOT NULL,
name TEXT UNIQUE NOT NULL,
price REAL NOT NULL,
owner TEXT NOT NULL,
created_at TEXT DEFAULT CURRENT_TIMESTAMP NOT NULL,
updated_at TEXT DEFAULT CURRENT_TIMESTAMP NOT NULL
);
CREATE TABLE orders (
id INTEGER PRIMARY KEY NOT NULL,
created_at TEXT DEFAULT CURRENT_TIMESTAMP NOT NULL,
updated_at TEXT DEFAULT CURRENT_TIMESTAMP NOT NULL
);
CREATE TABLE orders_products (
order_id INTEGER NOT NULL,
product_id INTEGER NOT NULL,
quantity INTEGER NOT NULL,
FOREIGN KEY (order_id) REFERENCES orders(id),
FOREIGN KEY (product_id) REFERENCES products(id),
PRIMARY KEY (order_id, product_id)
);
INSERT INTO products (name, price, owner)
VALUES
("Pfadiburger", 5.1, "Pfadfinder"),
("Kuchen", 2, "Sportunion"),
("Apfelsaft", 1.5, "Sportunion"),
("Käsekrainer", 4, "Pfadfinder"),
("Süßes", 0.2, "Pfadfinder"),
("Capuccino", 3.5, "Deluke"),
("Espresso", 2.5, "Deluke");
INSERT INTO orders DEFAULT VALUES;
INSERT INTO orders_products (order_id, product_id, quantity)
VALUES
(1, 1, 3),
(1, 2, 1),
(1, 5, 1);
INSERT INTO orders DEFAULT VALUES;
INSERT INTO orders_products (order_id, product_id, quantity)
VALUES
(2, 4, 2),
(2, 6, 2),
(2, 2, 1);
CREATE VIEW totals_per_owner_and_order AS
SELECT id, owner, SUM(total_price) AS total FROM (
SELECT o.id, p.owner, p.price*op.quantity AS total_price FROM orders AS o
INNER JOIN orders_products AS op ON o.id = op.order_id
INNER JOIN products AS p ON p.id = op.product_id
)
GROUP BY id, owner;

61
src/db.rs Normal file
View File

@ -0,0 +1,61 @@
pub mod models;
pub mod schema;
use anyhow::Result;
use diesel::prelude::*;
use dotenv::dotenv;
use std::env;
use self::{models::*, schema::*};
pub fn establish_connection() -> SqliteConnection {
dotenv().ok();
let db_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
SqliteConnection::establish(&db_url)
.unwrap_or_else(|_| panic!("Error connecting to {}", db_url))
}
pub fn get_products() -> Vec<Product> {
use self::schema::products::dsl::*;
let conn = &mut establish_connection();
products
.load::<Product>(conn)
.expect("Error loading products")
}
pub fn get_products_from_order(order: &Order, conn: &mut SqliteConnection) -> Vec<Product> {
let res: Vec<(OrderProduct, Product)> = OrderProduct::belonging_to(order)
.inner_join(products::table)
.get_results(conn);
// Strip off all the elements from the linking table
res.into_iter().map(|(_ri, i)| i).collect()
}
pub fn create_product(
conn: &mut SqliteConnection,
name: &str,
price: &f32,
owner: &str,
) -> Product {
let new_product = NewProduct { name, price, owner };
diesel::insert_into(products::table)
.values(&new_product)
.get_result(conn)
.expect("Error saving new product")
}
pub fn create_order(
conn: &mut SqliteConnection,
products: Vec<Product>,
) -> Result<(Order, Vec<Product>)> {
let order = diesel::insert_into(orders::table)
.default_values()
.get_result(conn)?;
for product in products {
let product_exists = diesel::select(diesel::dsl::exists(products.filter(name.eq(product.name))))
.get_result(conn);
}
}

43
src/main.rs Normal file
View File

@ -0,0 +1,43 @@
use serde::{Deserialize, Serialize};
use dotenv;
use sqlx::{sqlite::SqlitePoolOptions, SqlitePool};
use tide::{Body, Request, Result};
#[derive(Deserialize, Serialize)]
struct Product {
name: String,
}
#[async_std::main]
async fn main() -> Result<()> {
dotenv::dotenv().ok();
pretty_env_logger::init();
let db_pool = make_db_pool().await;
let mut app = tide::new();
app.at("/products").post(create_product);
app.listen("127.0.0.1:8080").await?;
Ok(())
}
pub async fn make_db_pool() -> SqlitePool {
let db_url =
std::env::var("DATABASE_URL").expect("Environment variable DATABASE_URL must be set");
let db_pool = SqlitePoolOptions::new()
.max_connections(2)
.connect(&format!("sqlite://{}?mode=rwc", &db_url))
.await
.expect("Could not connect to database");
db_pool
}
async fn create_product(mut req: Request<()>) -> Result<Body> {
let product: Product = req.body_json().await?;
println!("product name: {}", product.name);
let product = Product {
name: "chashu".into(),
};
Body::from_json(&product)
}