Add operations & node_type check triggers

This commit is contained in:
GHOSCHT 2024-05-10 23:08:03 +02:00
parent 04d3c775f8
commit 0120de27bf
Signed by: ghoscht
GPG key ID: 2C2C1C62A5388E82
9 changed files with 204 additions and 19 deletions

View file

@ -10,4 +10,6 @@ DROP TABLE images;
DROP TABLE meal_images;
DROP TYPE node_type;
DROP FUNCTION check_node_type();
DROP FUNCTION check_linked_restaurants();
DROP EXTENSION postgis CASCADE;

View file

@ -4,17 +4,53 @@ CREATE EXTENSION postgis;
CREATE TABLE nodes(
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
type NODE_TYPE NOT NULL,
node_type NODE_TYPE NOT NULL,
coordinates GEOMETRY(POINT,4326) NOT NULL
);
CREATE OR REPLACE FUNCTION check_linked_restaurants()
RETURNS TRIGGER AS $$
BEGIN
-- Check if the node is being updated from 'restaurant' to a different type
IF OLD.node_type = 'restaurant' AND NEW.node_type <> 'restaurant' THEN
-- Check if the node still has linked restaurants
IF EXISTS (SELECT 1 FROM restaurants WHERE node_id = OLD.id) THEN
RAISE EXCEPTION 'Cannot change node type from "restaurant" as it still has linked restaurants';
END IF;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER check_linked_restaurants_trigger
BEFORE UPDATE OF node_type ON nodes
FOR EACH ROW
EXECUTE FUNCTION check_linked_restaurants();
CREATE TABLE restaurants(
id SERIAL PRIMARY KEY,
node_id INTEGER REFERENCES nodes(id) NOT NULL,
address VARCHAR(30) NOT NULL,
price INTEGER CHECK ( price >= 0 AND price <= 10 ) NOT NULL
price SMALLINT CHECK ( price >= 0 AND price <= 10 ) NOT NULL
);
CREATE FUNCTION check_node_type()
RETURNS TRIGGER AS $$
BEGIN
-- Check if the node referenced by the foreign key is of type 'restaurant'
IF (SELECT node_type FROM nodes WHERE id = NEW.node_id) <> 'restaurant' THEN
RAISE EXCEPTION 'The referenced node has not type "restaurant"';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER enforce_node_type
BEFORE INSERT OR UPDATE ON restaurants
FOR EACH ROW
EXECUTE FUNCTION check_node_type();
CREATE TABLE images(
id SERIAL PRIMARY KEY,
url VARCHAR(50) NOT NULL
@ -41,7 +77,7 @@ CREATE TABLE meals(
restaurant_rating_id INTEGER REFERENCES restaurant_ratings(id) NOT NULL,
user_id INTEGER REFERENCES users(id) NOT NULL,
name VARCHAR(30) NOT NULL,
rating INTEGER CHECK ( rating >= 0 AND rating <= 10 ) NOT NULL,
rating SMALLINT CHECK ( rating >= 0 AND rating <= 10 ) NOT NULL,
price DECIMAL(12,2) CHECK (price >= 0) NOT NULL,
price_currency VARCHAR(1) CHECK (TRIM(price_currency) <> '') NOT NULL,
note VARCHAR(100) NOT NULL DEFAULT '',

View file

@ -1,6 +1,21 @@
--- src/full_schema.rs 2024-05-10 11:34:46.376360145 +0200
+++ src/schema.rs 2024-05-10 11:34:24.009031704 +0200
@@ -52,13 +52,12 @@
--- src/full_schema.rs 2024-05-10 22:44:39.336282167 +0200
+++ src/schema.rs 2024-05-10 22:45:22.991271745 +0200
@@ -1,14 +1,10 @@
// @generated automatically by Diesel CLI.
pub mod sql_types {
#[derive(diesel::query_builder::QueryId, diesel::sql_types::SqlType)]
- #[diesel(postgres_type(name = "geometry"))]
- pub struct Geometry;
-
- #[derive(diesel::query_builder::QueryId, diesel::sql_types::SqlType)]
#[diesel(postgres_type(name = "node_type"))]
pub struct NodeType;
}
diesel::table! {
use diesel::sql_types::*;
@@ -52,13 +48,12 @@
}
diesel::table! {
@ -13,4 +28,4 @@
id -> Int4,
#[max_length = 100]
name -> Varchar,
#[sql_name = "type"]
node_type -> NodeType,

View file

@ -3,7 +3,12 @@ extern crate diesel;
mod db;
mod models;
mod ops;
mod schema;
use diesel::prelude::*;
fn main() {}
fn main() {
ops::node_ops::create_node();
ops::restaurant_ops::create_restaurant();
// ops::node_ops::update_node();
ops::node_ops::show_nodes();
}

View file

@ -1,4 +1,4 @@
use crate::schema::nodes;
use crate::schema::{nodes, restaurants};
use diesel::prelude::*;
use postgis_diesel::types::Point;
@ -13,6 +13,30 @@ pub enum NodeType {
#[diesel(table_name = nodes)]
pub struct NewNode<'a> {
pub name: &'a str,
pub type_: NodeType,
pub node_type: NodeType,
pub coordinates: Point,
}
#[derive(Debug, Queryable, AsChangeset)]
pub struct Node {
pub id: i32,
pub name: String,
pub node_type: NodeType,
pub coordinates: Point,
}
#[derive(Insertable)]
#[diesel(table_name = restaurants)]
pub struct NewRestaurant<'a> {
pub node_id: i32,
pub address: &'a str,
pub price: i16,
}
#[derive(Debug, Queryable, AsChangeset)]
pub struct Restaurant {
pub id: i32,
pub node_id: i32,
pub address: String,
pub price: i16,
}

2
src/ops.rs Normal file
View file

@ -0,0 +1,2 @@
pub mod node_ops;
pub mod restaurant_ops;

55
src/ops/node_ops.rs Normal file
View file

@ -0,0 +1,55 @@
use crate::db::establish_connection;
use crate::models::*;
use diesel::prelude::*;
pub fn create_node() {
use crate::schema::nodes::dsl::*;
let mut conn = establish_connection();
let new_node = NewNode {
name: "Foo",
node_type: NodeType::Restaurant,
coordinates: postgis_diesel::types::Point {
x: 0.0,
y: 0.0,
srid: Some(4326),
},
};
diesel::insert_into(nodes)
.values(&new_node)
.execute(&mut conn)
.expect("Error saving new Node");
}
pub fn update_node() {
use crate::schema::nodes::dsl::*;
let node_id = 1;
let mut conn = establish_connection();
let node = Node {
id: node_id,
name: "Bar".to_string(),
node_type: NodeType::Marker,
coordinates: postgis_diesel::types::Point {
x: 6.9,
y: 0.0,
srid: Some(4326),
},
};
diesel::update(nodes.find(node_id))
.set(&node)
.execute(&mut conn)
.expect("Error saving new Node");
}
pub fn show_nodes() {
use crate::schema::nodes::dsl::*;
let mut conn = establish_connection();
let results = nodes.load::<Node>(&mut conn).expect("Error loading Nodes");
println!("{:?}", results);
}

51
src/ops/restaurant_ops.rs Normal file
View file

@ -0,0 +1,51 @@
use crate::db::establish_connection;
use crate::models::*;
use diesel::prelude::*;
pub fn create_restaurant() {
use crate::schema::restaurants::dsl::*;
let mut conn = establish_connection();
let new_node = NewRestaurant {
node_id: 1,
address: "Hauptstraße 8",
price: 1,
};
diesel::insert_into(restaurants)
.values(&new_node)
.execute(&mut conn)
.expect("Error saving new Node");
}
// pub fn update_node() {
// use crate::schema::nodes::dsl::*;
//
// let node_id = 1;
// let mut conn = establish_connection();
//
// let node = Node {
// id: node_id,
// name: "Bar".to_string(),
// type_: NodeType::Restaurant,
// coordinates: postgis_diesel::types::Point {
// x: 6.9,
// y: 0.0,
// srid: Some(4326),
// },
// };
//
// diesel::update(nodes.find(node_id))
// .set(&node)
// .execute(&mut conn)
// .expect("Error saving new Node");
// }
//
// pub fn show_nodes() {
// use crate::schema::nodes::dsl::*;
//
// let mut conn = establish_connection();
// let results = nodes.load::<Node>(&mut conn).expect("Error loading Nodes");
// println!("{:?}", results);
// }

View file

@ -1,10 +1,6 @@
// @generated automatically by Diesel CLI.
pub mod sql_types {
#[derive(diesel::query_builder::QueryId, diesel::sql_types::SqlType)]
#[diesel(postgres_type(name = "geometry"))]
pub struct Geometry;
#[derive(diesel::query_builder::QueryId, diesel::sql_types::SqlType)]
#[diesel(postgres_type(name = "node_type"))]
pub struct NodeType;
@ -41,7 +37,7 @@ diesel::table! {
user_id -> Int4,
#[max_length = 30]
name -> Varchar,
rating -> Int4,
rating -> Int2,
price -> Numeric,
#[max_length = 1]
price_currency -> Varchar,
@ -60,8 +56,7 @@ diesel::table! {
id -> Int4,
#[max_length = 100]
name -> Varchar,
#[sql_name = "type"]
type_ -> NodeType,
node_type -> NodeType,
coordinates -> Geometry,
}
}
@ -88,7 +83,7 @@ diesel::table! {
node_id -> Int4,
#[max_length = 30]
address -> Varchar,
price -> Int4,
price -> Int2,
}
}