Initial version
This commit is contained in:
1
.env
Normal file
1
.env
Normal file
@@ -0,0 +1 @@
|
||||
DATABASE_URL=postgres://postgres:postgres@localhost:6666/lootakalenteri
|
||||
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
12
.idea/dataSources.xml
generated
Normal file
12
.idea/dataSources.xml
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||
<data-source source="LOCAL" name="lootakalenteri@localhost" uuid="2867adad-51b1-40f6-8817-ced1e914c0e3">
|
||||
<driver-ref>postgresql</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
|
||||
<jdbc-url>jdbc:postgresql://localhost:6666/lootakalenteri</jdbc-url>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
||||
11
.idea/lootakalenteri-backend.iml
generated
Normal file
11
.idea/lootakalenteri-backend.iml
generated
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="EMPTY_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/lootakalenteri-backend.iml" filepath="$PROJECT_DIR$/.idea/lootakalenteri-backend.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
7
.idea/sqldialects.xml
generated
Normal file
7
.idea/sqldialects.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="SqlDialectMappings">
|
||||
<file url="file://$PROJECT_DIR$/migrations/2025-04-10-064257_create_lootakalenteri/up.sql" dialect="PostgreSQL" />
|
||||
<file url="PROJECT" dialect="PostgreSQL" />
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
2041
Cargo.lock
generated
Normal file
2041
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
15
Cargo.toml
Normal file
15
Cargo.toml
Normal file
@@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "lootakalenteri-backend"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
diesel = { version = "2.2.9", features = ["postgres", "uuid", "r2d2", "chrono"] }
|
||||
uuid = "1.8.0"
|
||||
dotenvy = "0.15.7"
|
||||
actix-web = "4.10.2"
|
||||
env_logger = "0.11.8"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
chrono = { version = "0.4.40", features = ["serde"] }
|
||||
serde_json = "1.0.51"
|
||||
actix-rt = "2.10.0"
|
||||
9
diesel.toml
Normal file
9
diesel.toml
Normal file
@@ -0,0 +1,9 @@
|
||||
# For documentation on how to configure this file,
|
||||
# see https://diesel.rs/guides/configuring-diesel-cli
|
||||
|
||||
[print_schema]
|
||||
file = "src/schema.rs"
|
||||
custom_type_derives = ["diesel::query_builder::QueryId", "Clone"]
|
||||
|
||||
[migrations_directory]
|
||||
dir = "/home/jani-pulkkinen/RustroverProjects/lootakalenteri-backend/migrations"
|
||||
0
migrations/.keep
Normal file
0
migrations/.keep
Normal file
6
migrations/00000000000000_diesel_initial_setup/down.sql
Normal file
6
migrations/00000000000000_diesel_initial_setup/down.sql
Normal file
@@ -0,0 +1,6 @@
|
||||
-- This file was automatically created by Diesel to setup helper functions
|
||||
-- and other internal bookkeeping. This file is safe to edit, any future
|
||||
-- changes will be added to existing projects as new migrations.
|
||||
|
||||
DROP FUNCTION IF EXISTS diesel_manage_updated_at(_tbl regclass);
|
||||
DROP FUNCTION IF EXISTS diesel_set_updated_at();
|
||||
36
migrations/00000000000000_diesel_initial_setup/up.sql
Normal file
36
migrations/00000000000000_diesel_initial_setup/up.sql
Normal file
@@ -0,0 +1,36 @@
|
||||
-- This file was automatically created by Diesel to setup helper functions
|
||||
-- and other internal bookkeeping. This file is safe to edit, any future
|
||||
-- changes will be added to existing projects as new migrations.
|
||||
|
||||
|
||||
|
||||
|
||||
-- Sets up a trigger for the given table to automatically set a column called
|
||||
-- `updated_at` whenever the row is modified (unless `updated_at` was included
|
||||
-- in the modified columns)
|
||||
--
|
||||
-- # Example
|
||||
--
|
||||
-- ```sql
|
||||
-- CREATE TABLE users (id SERIAL PRIMARY KEY, updated_at TIMESTAMP NOT NULL DEFAULT NOW());
|
||||
--
|
||||
-- SELECT diesel_manage_updated_at('users');
|
||||
-- ```
|
||||
CREATE OR REPLACE FUNCTION diesel_manage_updated_at(_tbl regclass) RETURNS VOID AS $$
|
||||
BEGIN
|
||||
EXECUTE format('CREATE TRIGGER set_updated_at BEFORE UPDATE ON %s
|
||||
FOR EACH ROW EXECUTE PROCEDURE diesel_set_updated_at()', _tbl);
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE OR REPLACE FUNCTION diesel_set_updated_at() RETURNS trigger AS $$
|
||||
BEGIN
|
||||
IF (
|
||||
NEW IS DISTINCT FROM OLD AND
|
||||
NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at
|
||||
) THEN
|
||||
NEW.updated_at := current_timestamp;
|
||||
END IF;
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
@@ -0,0 +1,4 @@
|
||||
-- This file should undo anything in `up.sql`
|
||||
drop table loota_customer;
|
||||
drop table loota_order;
|
||||
drop table loota_box;
|
||||
34
migrations/2025-04-10-064257_create_lootakalenteri/up.sql
Normal file
34
migrations/2025-04-10-064257_create_lootakalenteri/up.sql
Normal file
@@ -0,0 +1,34 @@
|
||||
-- Lootakalenteri migration tables
|
||||
create table loota_customer
|
||||
(
|
||||
id uuid primary key not null default gen_random_uuid(),
|
||||
identifier varchar not null,
|
||||
created_time timestamp with time zone not null default now()
|
||||
);
|
||||
|
||||
create table loota_order
|
||||
(
|
||||
id uuid primary key not null default gen_random_uuid(),
|
||||
customer_id uuid not null,
|
||||
location varchar not null,
|
||||
created_time timestamp with time zone not null default now()
|
||||
);
|
||||
|
||||
alter table loota_order
|
||||
add constraint fk_customer_id foreign key (customer_id)
|
||||
references loota_customer (id) on delete cascade;
|
||||
|
||||
|
||||
|
||||
create table loota_box
|
||||
(
|
||||
id uuid primary key not null default gen_random_uuid(),
|
||||
order_id uuid not null,
|
||||
delivery_date timestamp with time zone,
|
||||
pickup_date timestamp with time zone,
|
||||
created_time timestamp with time zone not null default now()
|
||||
);
|
||||
|
||||
alter table loota_box
|
||||
add constraint fk_order_id foreign key (order_id)
|
||||
references loota_order (id) on delete cascade;
|
||||
2
migrations/2025-04-10-074116_test_data/down.sql
Normal file
2
migrations/2025-04-10-074116_test_data/down.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
-- This file should undo anything in `up.sql`
|
||||
delete from loota_customer;
|
||||
17
migrations/2025-04-10-074116_test_data/up.sql
Normal file
17
migrations/2025-04-10-074116_test_data/up.sql
Normal file
@@ -0,0 +1,17 @@
|
||||
-- Test data
|
||||
|
||||
insert into loota_customer (identifier) values ( 'customer1');
|
||||
insert into loota_customer (identifier) values ( 'customer2');
|
||||
|
||||
insert into loota_order (customer_id, location) values ( (select id from loota_customer where identifier = 'customer1'), 'location1');
|
||||
insert into loota_order (customer_id, location) values ( (select id from loota_customer where identifier = 'customer2'), 'location1');
|
||||
|
||||
insert into loota_box (order_id, delivery_date) values ( (select id from loota_order where customer_id = (select id from loota_customer where identifier = 'customer1')), '2025-04-15 10:00:00+00');
|
||||
insert into loota_box (order_id, delivery_date) values ( (select id from loota_order where customer_id = (select id from loota_customer where identifier = 'customer1')), '2025-04-16 10:00:00+00');
|
||||
insert into loota_box (order_id, delivery_date) values ( (select id from loota_order where customer_id = (select id from loota_customer where identifier = 'customer1')), '2025-04-17 10:00:00+00');
|
||||
insert into loota_box (order_id, delivery_date) values ( (select id from loota_order where customer_id = (select id from loota_customer where identifier = 'customer1')), '2025-04-18 10:00:00+00');
|
||||
|
||||
insert into loota_box (order_id, delivery_date) values ( (select id from loota_order where customer_id = (select id from loota_customer where identifier = 'customer2')), '2025-04-15 10:00:00+00');
|
||||
insert into loota_box (order_id, delivery_date) values ( (select id from loota_order where customer_id = (select id from loota_customer where identifier = 'customer2')), '2025-05-16 10:00:00+00');
|
||||
insert into loota_box (order_id, delivery_date) values ( (select id from loota_order where customer_id = (select id from loota_customer where identifier = 'customer2')), '2025-06-17 10:00:00+00');
|
||||
insert into loota_box (order_id, delivery_date) values ( (select id from loota_order where customer_id = (select id from loota_customer where identifier = 'customer2')), '2025-07-18 10:00:00+00');
|
||||
12
src/connection.rs
Normal file
12
src/connection.rs
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
use diesel::prelude::*;
|
||||
use dotenvy::dotenv;
|
||||
use std::env;
|
||||
|
||||
pub fn establish_connection() -> PgConnection {
|
||||
dotenv().ok();
|
||||
|
||||
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
|
||||
PgConnection::establish(&database_url)
|
||||
.unwrap_or_else(|_| panic!("Error connecting to {}", database_url))
|
||||
}
|
||||
1
src/constants.rs
Normal file
1
src/constants.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub const APPLICATION_JSON: &str = "application/json";
|
||||
193
src/loota.rs
Normal file
193
src/loota.rs
Normal file
@@ -0,0 +1,193 @@
|
||||
use actix_web::{get, post, web, HttpResponse, Responder};
|
||||
use chrono::{NaiveDateTime};
|
||||
use diesel::prelude::*;
|
||||
use diesel::result::Error;
|
||||
use uuid::Uuid;
|
||||
use crate::constants::APPLICATION_JSON;
|
||||
use crate::connection::establish_connection;
|
||||
use crate::models::{Customer, Box, Order, LootaResponse, LootaBoxResponse, LootaRequest};
|
||||
use crate::schema::loota_box::dsl::loota_box;
|
||||
use crate::schema::loota_box::{delivery_date, id, pickup_date};
|
||||
use crate::schema::loota_customer::dsl::loota_customer;
|
||||
use crate::schema::loota_customer::identifier;
|
||||
|
||||
fn find_boxes(_identifier: String, _order: &Order, conn: &mut PgConnection) -> LootaResponse {
|
||||
let boxes = Box::belonging_to(_order)
|
||||
.select(Box::as_select())
|
||||
.order_by(delivery_date.asc())
|
||||
.load(conn);
|
||||
|
||||
match boxes {
|
||||
Ok(boxes) => {
|
||||
let _box_responses = boxes.iter().map(|b| {
|
||||
LootaBoxResponse {
|
||||
id: b.id.to_string(),
|
||||
delivery_date: b.delivery_date,
|
||||
pickup_date: b.pickup_date,
|
||||
}
|
||||
});
|
||||
|
||||
LootaResponse {
|
||||
identifier: _identifier.clone(),
|
||||
location: _order.location.clone(),
|
||||
boxes: _box_responses.collect(),
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Error: {:?}", err);
|
||||
LootaResponse {
|
||||
identifier: "".to_string(),
|
||||
location: "".to_string(),
|
||||
boxes: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn find_order(_customer: &Customer, conn: &mut PgConnection) -> Result<LootaResponse, Error> {
|
||||
let _identifier = _customer.identifier.clone();
|
||||
let order = Order::belonging_to(_customer)
|
||||
.select(Order::as_select())
|
||||
.limit(1)
|
||||
.load(conn);
|
||||
|
||||
match order {
|
||||
Ok(order) => match order.first() {
|
||||
Some(order) => Ok(find_boxes(_identifier, order, conn)),
|
||||
_ => Err(Error::NotFound)
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Error: {:?}", err);
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
fn find_customer(_identifier: String) -> Result<LootaResponse, Error> {
|
||||
let conn = &mut establish_connection();
|
||||
|
||||
let customer = loota_customer
|
||||
.filter(identifier.eq(_identifier))
|
||||
.select(Customer::as_select())
|
||||
.load(conn);
|
||||
|
||||
match customer {
|
||||
Ok(customer) => match customer.first() {
|
||||
Some(customer) => Ok(find_order(customer, conn)?),
|
||||
_ => Err(Error::NotFound)
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Error: {:?}", err);
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn update_box(_id: Uuid, _pickup_date: NaiveDateTime) -> Result<LootaBoxResponse, Error> {
|
||||
let conn = &mut establish_connection();
|
||||
|
||||
let loota = diesel::update(loota_box.filter(id.eq(&_id)))
|
||||
.set(pickup_date.eq(_pickup_date))
|
||||
.returning(Box::as_returning())
|
||||
.get_result(conn);
|
||||
|
||||
match loota {
|
||||
Ok(loota) => {
|
||||
Ok(LootaBoxResponse {
|
||||
id: loota.id.to_string(),
|
||||
delivery_date: loota.delivery_date,
|
||||
pickup_date: loota.pickup_date,
|
||||
})
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Error: {:?}", err);
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn parse_uuid(_id: String) -> Result<Uuid, uuid::Error> {
|
||||
Uuid::parse_str(&_id)
|
||||
}
|
||||
|
||||
fn parse_date(_date: String) -> Result<NaiveDateTime, chrono::ParseError> {
|
||||
NaiveDateTime::parse_from_str(&_date, "%Y-%m-%dT%H:%M:%S")
|
||||
}
|
||||
|
||||
#[get("/loota/{id}")]
|
||||
async fn get(path: web::Path<String>) -> impl Responder {
|
||||
let identifer = path.into_inner();
|
||||
println!("id: {:?}", identifer);
|
||||
|
||||
let response = web::block(move || find_customer(identifer)).await.unwrap();
|
||||
|
||||
match response {
|
||||
Ok(response) => {
|
||||
HttpResponse::Ok()
|
||||
.content_type(APPLICATION_JSON).json(response)
|
||||
}
|
||||
_ => HttpResponse::NotFound()
|
||||
.content_type(APPLICATION_JSON)
|
||||
.await
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
#[post("/loota/")]
|
||||
async fn update(req: web::Json<LootaRequest>) -> impl Responder {
|
||||
let box_id = parse_uuid(req.id.clone());
|
||||
|
||||
match box_id {
|
||||
Ok(box_id) => {
|
||||
|
||||
let date = parse_date(req.pickup_date.clone());
|
||||
match date {
|
||||
Ok(date) => {
|
||||
|
||||
let updated_box = update_box(box_id, date);
|
||||
match updated_box {
|
||||
Ok(updated_box) => {
|
||||
HttpResponse::Ok()
|
||||
.content_type(APPLICATION_JSON)
|
||||
.json(updated_box)
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Error: {:?}", err);
|
||||
HttpResponse::BadRequest()
|
||||
.content_type(APPLICATION_JSON)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Error: {:?}", err);
|
||||
HttpResponse::BadRequest()
|
||||
.content_type(APPLICATION_JSON)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Error: {:?}", err);
|
||||
HttpResponse::BadRequest()
|
||||
.content_type(APPLICATION_JSON)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
35
src/main.rs
Normal file
35
src/main.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
extern crate actix_web;
|
||||
extern crate diesel;
|
||||
use std::{io};
|
||||
|
||||
|
||||
use actix_web::{middleware, App, HttpServer};
|
||||
use diesel::r2d2::{ConnectionManager, Pool, PooledConnection};
|
||||
use diesel::PgConnection;
|
||||
|
||||
mod constants;
|
||||
mod loota;
|
||||
mod models;
|
||||
mod schema;
|
||||
mod connection;
|
||||
|
||||
pub type DBPool = Pool<ConnectionManager<PgConnection>>;
|
||||
pub type DBPooledConnection = PooledConnection<ConnectionManager<PgConnection>>;
|
||||
|
||||
|
||||
#[actix_rt::main]
|
||||
async fn main() -> io::Result<()> {
|
||||
env_logger::init();
|
||||
|
||||
HttpServer::new(|| {
|
||||
App::new()
|
||||
// enable logger - always register actix-web Logger middleware last
|
||||
.wrap(middleware::Logger::default())
|
||||
// register HTTP requests handlers
|
||||
.service(loota::get)
|
||||
.service(loota::update)
|
||||
})
|
||||
.bind("0.0.0.0:9090")?
|
||||
.run()
|
||||
.await
|
||||
}
|
||||
55
src/models.rs
Normal file
55
src/models.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
use uuid::Uuid;
|
||||
use diesel::prelude::*;
|
||||
use chrono::{NaiveDateTime};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use crate::schema::{loota_customer, loota_order, loota_box};
|
||||
|
||||
|
||||
#[derive(Queryable, Identifiable, Selectable, Debug, PartialEq)]
|
||||
#[diesel(table_name = loota_customer)]
|
||||
pub struct Customer {
|
||||
pub id: Uuid,
|
||||
pub identifier: String
|
||||
}
|
||||
|
||||
#[derive(Queryable, Selectable, Identifiable, Associations, Debug, PartialEq)]
|
||||
#[diesel(belongs_to(Customer))]
|
||||
#[diesel(table_name = loota_order)]
|
||||
pub struct Order {
|
||||
pub id: Uuid,
|
||||
pub location: String,
|
||||
pub customer_id: Uuid,
|
||||
}
|
||||
|
||||
#[derive(Queryable, Selectable, Identifiable, Associations, Debug, PartialEq)]
|
||||
#[diesel(belongs_to(Order))]
|
||||
#[diesel(table_name = loota_box)]
|
||||
#[diesel(check_for_backend(diesel::pg::Pg))]
|
||||
pub struct Box {
|
||||
pub id: Uuid,
|
||||
pub delivery_date: Option<NaiveDateTime>,
|
||||
pub pickup_date: Option<NaiveDateTime>,
|
||||
pub order_id: Uuid
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct LootaResponse {
|
||||
pub identifier: String,
|
||||
pub location: String,
|
||||
pub boxes: Vec<LootaBoxResponse>
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct LootaBoxResponse {
|
||||
pub id: String,
|
||||
pub delivery_date: Option<NaiveDateTime>,
|
||||
pub pickup_date: Option<NaiveDateTime>
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct LootaRequest {
|
||||
pub id: String,
|
||||
pub pickup_date: String
|
||||
}
|
||||
37
src/schema.rs
Normal file
37
src/schema.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
// @generated automatically by Diesel CLI.
|
||||
|
||||
diesel::table! {
|
||||
loota_box (id) {
|
||||
id -> Uuid,
|
||||
order_id -> Uuid,
|
||||
delivery_date -> Nullable<Timestamp>,
|
||||
pickup_date -> Nullable<Timestamp>,
|
||||
created_time -> Timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
loota_customer (id) {
|
||||
id -> Uuid,
|
||||
identifier -> Varchar,
|
||||
created_time -> Timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
loota_order (id) {
|
||||
id -> Uuid,
|
||||
customer_id -> Uuid,
|
||||
location -> Varchar,
|
||||
created_time -> Timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::joinable!(loota_box -> loota_order (order_id));
|
||||
diesel::joinable!(loota_order -> loota_customer (customer_id));
|
||||
|
||||
diesel::allow_tables_to_appear_in_same_query!(
|
||||
loota_box,
|
||||
loota_customer,
|
||||
loota_order,
|
||||
);
|
||||
Reference in New Issue
Block a user