diff --git a/api/auth/middleware/authentication_middleware.go b/api/auth/middleware/authentication_middleware.go index 2c1e485..cc671a6 100644 --- a/api/auth/middleware/authentication_middleware.go +++ b/api/auth/middleware/authentication_middleware.go @@ -156,8 +156,7 @@ func IsAuthenticated(auth *auth.Authenticator) gin.HandlerFunc { context.Next() } else { if !HandleRefreshToken(session) { - context.String(http.StatusUnauthorized, "Failed to refresh access token") - context.Abort() + context.Redirect(http.StatusSeeOther, "/auth/login") return } else { context.Next() diff --git a/api/auth/middleware/verification_middleware.go b/api/auth/middleware/verification_middleware.go index 34cd504..c1518cc 100644 --- a/api/auth/middleware/verification_middleware.go +++ b/api/auth/middleware/verification_middleware.go @@ -33,6 +33,8 @@ func UserInDatabase(pool *pgxpool.Pool) gin.HandlerFunc { return } + log.Printf("%d", count) + if count == 0 { _, exec_err := conn.Exec(context.Background(), queries.USER_CREATE_QUERY, sub_id, nickname) diff --git a/api/controllers/itemController.go b/api/controllers/itemController.go index aa63856..f43d39a 100644 --- a/api/controllers/itemController.go +++ b/api/controllers/itemController.go @@ -217,6 +217,14 @@ func AddItemToOrder(pool *pgxpool.Pool) gin.HandlerFunc { return } + _, update_order_filled_exec_err := conn.Exec(context.Background(), queries.SET_ORDER_FILLED, false, order_id) + + if update_order_filled_exec_err != nil { + ctx.String(http.StatusInternalServerError, "AddItemToOrder(): ERROR... failed to set order state") + log.Printf("AddItemToOrder(): ERROR... failed to set order state... %s", update_order_filled_exec_err.Error()) + return + } + var order_item_price dto.OrderItemPriceResponse price_data_row := conn.QueryRow(context.Background(), queries.GET_ORDER_ITEM_PRICE, item_id, order_id) @@ -281,3 +289,150 @@ func GetOrderItems(pool *pgxpool.Pool) gin.HandlerFunc { ctx.JSON(http.StatusOK, items) } } + +func SetItemMade(pool *pgxpool.Pool) gin.HandlerFunc { + return func(ctx *gin.Context) { + conn, conn_err := pool.Acquire(ctx) + if conn_err != nil { + log.Printf("SetItemMade(): ERROR: Failed to connect... %s", conn_err.Error()) + ctx.AbortWithStatus(http.StatusInternalServerError) + return + } + defer conn.Release() + + var request dto.ItemOrderSetMadeRequest + request_read_err := ctx.ShouldBindJSON(&request) + if request_read_err != nil { + ctx.String(http.StatusBadRequest, "SetItemMade(): ERROR... Error Request in bad format") + return + } + + _, exec_set_made_err := conn.Exec(context.Background(), queries.SET_MADE, request.Made, request.ItemId, request.OrderId) + + if exec_set_made_err != nil { + ctx.String(http.StatusInternalServerError, "SetItemMade(): ERROR... Internal server error") + log.Printf("SetItemMade(): ERROR... Failed to set item made... %s", exec_set_made_err.Error()) + return + } + + _, exec_update_order_err := conn.Exec(context.Background(), queries.UPDATE_ORDER_FILLED, request.OrderId) + if exec_update_order_err != nil { + ctx.String(http.StatusInternalServerError, "SetItemMade(): ERROR... Failed to update order") + log.Printf("SetItemMade(): ERROR... Failed to update order... %s", exec_update_order_err.Error()) + return + } + + var order_filled dto.OrderFilledResponse + scan_err := conn.QueryRow(context.Background(), queries.GET_ORDER_MADE_DETAILS, request.OrderId).Scan(&order_filled.OrderId, &order_filled.Filled) + if scan_err != nil { + if scan_err == pgx.ErrNoRows { + ctx.String(http.StatusBadRequest, "SetItemMade(): Invalid data") + return + } + ctx.String(http.StatusInternalServerError, "SetItemMade(): ERROR... Error querying result") + log.Printf("SetItemMade(): ERROR... Error querying result... %s", scan_err.Error()) + return + } + + ctx.JSON(http.StatusOK, order_filled) + } +} +func SetItemQuantity(pool *pgxpool.Pool) gin.HandlerFunc { + return func(ctx *gin.Context) { + conn, conn_err := pool.Acquire(ctx) + if conn_err != nil { + log.Printf("SetItemMade(): ERROR: Failed to connect... %s", conn_err.Error()) + ctx.AbortWithStatus(http.StatusInternalServerError) + return + } + defer conn.Release() + + var request dto.ItemOrderSetQuantityRequest + request_read_err := ctx.ShouldBindJSON(&request) + if request_read_err != nil { + ctx.String(http.StatusBadRequest, "SetItemQuantity(): ERROR... Error Request in bad format") + return + } + + _, exec_set_quantity_err := conn.Exec(context.Background(), queries.SET_QUANTITY, request.Quantity, request.ItemId, request.OrderId) + + if exec_set_quantity_err != nil { + ctx.String(http.StatusInternalServerError, "SetItemMade(): ERROR... Internal server error") + log.Printf("SetItemQuantity(): ERROR... Failed to set item quantity... %s", exec_set_quantity_err.Error()) + return + } + + _, exec_update_order_err := conn.Exec(context.Background(), queries.UPDATE_ORDER_FILLED, request.OrderId) + if exec_update_order_err != nil { + ctx.String(http.StatusInternalServerError, "SetItemMade(): ERROR... Failed to update order") + log.Printf("SetItemQuantity(): ERROR... Failed to update order... %s", exec_update_order_err.Error()) + return + } + + var order_filled dto.OrderFilledResponse + scan_err := conn.QueryRow(context.Background(), queries.GET_ORDER_MADE_DETAILS, request.OrderId).Scan(&order_filled.OrderId, &order_filled.Filled) + if scan_err != nil { + if scan_err == pgx.ErrNoRows { + ctx.String(http.StatusBadRequest, "SetItemQuantity(): Invalid data") + return + } + ctx.String(http.StatusInternalServerError, "SetItemQuantity(): ERROR... Error querying result") + log.Printf("SetItemQuantity(): ERROR... Error querying result... %s", scan_err.Error()) + return + } + + ctx.JSON(http.StatusOK, order_filled) + } +} + +func DeleteOrderItem(pool *pgxpool.Pool) gin.HandlerFunc { + return func(ctx *gin.Context) { + conn, conn_err := pool.Acquire(ctx) + if conn_err != nil { + log.Printf("DeleteOrderItem(): ERROR: Failed to connect... %s", conn_err.Error()) + ctx.AbortWithStatus(http.StatusInternalServerError) + return + } + defer conn.Release() + + var request dto.DeleteOrderItemRequest + request_read_err := ctx.ShouldBindJSON(&request) + if request_read_err != nil { + ctx.String(http.StatusBadRequest, "DeleteOrderItem(): ERROR... invalid request") + return + } + + _, exec_err := conn.Exec(context.Background(), queries.REMOVE_ITEM_FROM_ORDER, request.ItemId, request.OrderId) + if exec_err != nil { + ctx.String(http.StatusInternalServerError, "DeleteOrderItem(): ERROR.. Failed to delete item") + log.Printf("DeleteOrderItem(): ERROR... Failed to delte item... %s", exec_err.Error()) + return + } + } +} + +func DeleteItem(pool *pgxpool.Pool) gin.HandlerFunc { + return func(ctx *gin.Context) { + conn, conn_err := pool.Acquire(ctx) + if conn_err != nil { + log.Printf("DeleteItem(): ERROR: Failed to connect... %s", conn_err.Error()) + ctx.AbortWithStatus(http.StatusInternalServerError) + return + } + defer conn.Release() + + item_id := ctx.Query("item_id") + item_id_int, parse_err := strconv.ParseInt(item_id, 10, 64) + if parse_err != nil || item_id == "" { + ctx.String(http.StatusBadRequest, "DeleteItem(): Invalid data entry") + return + } + + _, exec_err := conn.Exec(context.Background(), "DELETE FROM item WHERE id = $1", item_id_int) + if exec_err != nil { + ctx.String(http.StatusInternalServerError, "DeleteItem(): Failed to delete item") + log.Printf("DeleteItem(): ERROR... Failed to delete item... %s", exec_err.Error()) + return + } + } +} diff --git a/api/controllers/orderController.go b/api/controllers/orderController.go index ac95052..d15c290 100644 --- a/api/controllers/orderController.go +++ b/api/controllers/orderController.go @@ -31,7 +31,7 @@ func CreateOrder(pool *pgxpool.Pool) gin.HandlerFunc { var current_user dto.UserResponse - user_query_err := conn.QueryRow(context.Background(), queries.GET_CURRENT_USER_OBJECT, sub_id).Scan(¤t_user.Id, ¤t_user.Name, ¤t_user.Job_Position, ¤t_user.Active, ¤t_user.Admin) + user_query_err := conn.QueryRow(context.Background(), queries.GET_CURRENT_USER_OBJECT, sub_id).Scan(¤t_user.Id, ¤t_user.Name, ¤t_user.JobPosition, ¤t_user.Active, ¤t_user.Admin) if user_query_err != nil { log.Printf("CreateOrder(): ERROR Failed to query user... %s", user_query_err.Error()) @@ -139,6 +139,14 @@ func GetOrderTable(pool *pgxpool.Pool) gin.HandlerFunc { return } + var table_query dto.OrderTableQuery + + bind_err := ctx.ShouldBindJSON(&table_query) + if bind_err != nil { + ctx.String(http.StatusBadRequest, "GetOrderTable(): ERROR... invalid query") + return + } + filter := ctx.Query("filter") filter_int, filter_parse_err := strconv.ParseInt(filter, 10, 64) if filter == "" || filter_parse_err != nil { @@ -147,7 +155,7 @@ func GetOrderTable(pool *pgxpool.Pool) gin.HandlerFunc { } query_string := utils.GetOrderTableQueryString(filter_int) - rows, query_err := conn.Query(context.Background(), query_string, utils.PAGE_SIZE*page_int, utils.PAGE_SIZE) + rows, query_err := conn.Query(context.Background(), query_string, utils.PAGE_SIZE*page_int, utils.PAGE_SIZE, table_query.Orderer, table_query.DateDue, table_query.DatePlaced) if query_err != nil { ctx.String(http.StatusInternalServerError, "GetOrdertable(): ERROR... internal server error") log.Printf("GetOrderTable(): ERROR... Failed to query table...\nQUERY: %s\n %s", query_string, query_err.Error()) @@ -172,8 +180,28 @@ func GetOrderTable(pool *pgxpool.Pool) gin.HandlerFunc { } } -func SetOrderFilled(pool *pgxpool.Pool) gin.HandlerFunc { +func DeleteOrder(pool *pgxpool.Pool) gin.HandlerFunc { return func(ctx *gin.Context) { + conn, conn_err := pool.Acquire(ctx) + if conn_err != nil { + log.Printf("DeleteOrder(): ERROR: Failed to connect... %s", conn_err.Error()) + ctx.AbortWithStatus(http.StatusInternalServerError) + return + } + defer conn.Release() + order_id := ctx.Query("order_id") + order_id_int, parse_err := strconv.ParseInt(order_id, 10, 64) + if parse_err != nil { + ctx.String(http.StatusBadRequest, "DeleteOrder(): Invalid input") + return + } + + _, exec_err := conn.Exec(context.Background(), "DELETE FROM order_record WHERE id = $1", order_id_int) + if exec_err != nil { + ctx.String(http.StatusInternalServerError, "DeleteOrder(): ERROR... failed to delete order") + log.Printf("DeleteOrder(): ERROR... Failed to delete order %s", exec_err.Error()) + return + } } } diff --git a/api/controllers/userController.go b/api/controllers/userController.go index 3106249..abe5eb0 100644 --- a/api/controllers/userController.go +++ b/api/controllers/userController.go @@ -21,6 +21,7 @@ func SetUserName(pool *pgxpool.Pool) gin.HandlerFunc { if err != nil { // TODO: Log this error ctx.String(http.StatusInternalServerError, err.Error()) + log.Printf("SetUserName(): ERROR... Failed to acquire connection... %s", err.Error()) return } user_profile, _ := ctx.Get("user_profile") @@ -109,6 +110,13 @@ func GetUserTable(pool *pgxpool.Pool) gin.HandlerFunc { } defer conn.Release() + var request dto.UserRequest + body_read_err := ctx.ShouldBindJSON(&request) + if body_read_err != nil { + ctx.String(http.StatusBadRequest, "GetUserTable(): ERROR... Invalid user query object") + return + } + page := ctx.Query("page") if page == "" { ctx.String(http.StatusBadRequest, "GetUserTable(): Missing page") @@ -119,7 +127,7 @@ func GetUserTable(pool *pgxpool.Pool) gin.HandlerFunc { ctx.String(http.StatusBadRequest, "GetUserTable(): Not an integer") return } - rows, query_err := conn.Query(context.Background(), queries.USER_GET_TABLE_DATA, page_int*utils.PAGE_SIZE, utils.PAGE_SIZE) + rows, query_err := conn.Query(context.Background(), queries.USER_GET_TABLE_DATA, page_int*utils.PAGE_SIZE, utils.PAGE_SIZE, request.Name, request.JobPosition) if query_err != nil { ctx.String(http.StatusInternalServerError, "GetUserTable(): Failed to query database...") log.Printf("GetUserTable(): ERROR... %s", query_err.Error()) @@ -129,7 +137,7 @@ func GetUserTable(pool *pgxpool.Pool) gin.HandlerFunc { var users []dto.UserResponse for rows.Next() { var user dto.UserResponse - scan_err := rows.Scan(&user.Id, &user.Name, &user.Job_Position, &user.Active, &user.Admin) + scan_err := rows.Scan(&user.Id, &user.Name, &user.JobPosition, &user.Active, &user.Admin) if scan_err != nil { ctx.String(http.StatusInternalServerError, "GetUserTable(): ERROR: Failed to scan..") log.Printf("GetUserTable(): ERROR... %s", scan_err.Error()) @@ -158,7 +166,7 @@ func GetCurrentAuthenticatedUser(pool *pgxpool.Pool) gin.HandlerFunc { var user dto.UserResponse - query_err := conn.QueryRow(context.Background(), queries.GET_CURRENT_USER_OBJECT, sub_id).Scan(&user.Id, &user.Name, &user.Job_Position, &user.Active, &user.Admin) + query_err := conn.QueryRow(context.Background(), queries.GET_CURRENT_USER_OBJECT, sub_id).Scan(&user.Id, &user.Name, &user.JobPosition, &user.Active, &user.Admin) if query_err != nil { ctx.String(http.StatusInternalServerError, "GetCurrentAuthenticatedUser(): ERROR.... Failed to query") log.Printf("GetCurrentAuthenticatedUser(): ERROR in querying user table... %s", query_err.Error()) diff --git a/api/dto/delete_order_item_request.go b/api/dto/delete_order_item_request.go new file mode 100644 index 0000000..570500e --- /dev/null +++ b/api/dto/delete_order_item_request.go @@ -0,0 +1,6 @@ +package dto + +type DeleteOrderItemRequest struct { + OrderId int `json:"order_id"` + ItemId int `json:"item_id"` +} diff --git a/api/dto/item_order_set_made_request.go b/api/dto/item_order_set_made_request.go new file mode 100644 index 0000000..1d67020 --- /dev/null +++ b/api/dto/item_order_set_made_request.go @@ -0,0 +1,7 @@ +package dto + +type ItemOrderSetMadeRequest struct { + OrderId int `json:"order_id"` + ItemId int `json:"item_id"` + Made int `json:"made"` +} diff --git a/api/dto/item_order_set_quantity_request.go b/api/dto/item_order_set_quantity_request.go new file mode 100644 index 0000000..a5ea64c --- /dev/null +++ b/api/dto/item_order_set_quantity_request.go @@ -0,0 +1,7 @@ +package dto + +type ItemOrderSetQuantityRequest struct { + OrderId int `json:"order_id"` + ItemId int `json:"item_id"` + Quantity int `json:"quantity"` +} diff --git a/api/dto/order_filled_response.go b/api/dto/order_filled_response.go new file mode 100644 index 0000000..00ce564 --- /dev/null +++ b/api/dto/order_filled_response.go @@ -0,0 +1,6 @@ +package dto + +type OrderFilledResponse struct { + OrderId int `json:"order_id"` + Filled bool `json:"filled"` +} diff --git a/api/dto/order_table_query.go b/api/dto/order_table_query.go new file mode 100644 index 0000000..92517f5 --- /dev/null +++ b/api/dto/order_table_query.go @@ -0,0 +1,7 @@ +package dto + +type OrderTableQuery struct { + Orderer string `json:"orderer"` + DateDue string `json:"date_due"` + DatePlaced string `json:"date_placed"` +} diff --git a/api/dto/user_request.go b/api/dto/user_request.go new file mode 100644 index 0000000..738a6ac --- /dev/null +++ b/api/dto/user_request.go @@ -0,0 +1,6 @@ +package dto + +type UserRequest struct { + Name string `json:"name"` + JobPosition string `json:"job_position"` +} diff --git a/api/dto/user_response.go b/api/dto/user_response.go index 004a9c1..86b2227 100644 --- a/api/dto/user_response.go +++ b/api/dto/user_response.go @@ -3,9 +3,9 @@ package dto // User response for exposing to the front-end // :3 type UserResponse struct { - Id int - Name string - Job_Position string - Active bool - Admin bool + Id int `json: "id"` + Name string `json: "name"` + JobPosition string `json: "job_position"` + Active bool `json: "active"` + Admin bool `json: "admin"` } diff --git a/api/main.go b/api/main.go index ae3ec13..ddbd175 100644 --- a/api/main.go +++ b/api/main.go @@ -84,8 +84,13 @@ func main() { router.PUT("/user/position", user_authenticated, middleware.GetUserProfile, user_in_db, user_active, user_is_admin, controllers.SetUserPosition(pool)) router.PUT("/item/price", user_authenticated, middleware.GetUserProfile, user_in_db, user_active, user_is_admin, controllers.SetItemPrice(pool)) router.PUT("/order/item", user_authenticated, middleware.GetUserProfile, user_in_db, user_active, controllers.AddItemToOrder(pool)) + router.PUT("/item/made", user_authenticated, middleware.GetUserProfile, user_in_db, user_active, controllers.SetItemMade(pool)) + router.PUT("/item/quantity", user_authenticated, middleware.GetUserProfile, user_in_db, user_active, controllers.SetItemQuantity(pool)) router.DELETE("/user/deactivate", middleware.IsAuthenticated(authenticator), middleware.GetUserProfile, user_in_db, user_active, user_is_admin, controllers.DeactivateUser(pool)) + router.DELETE("/order/item", user_authenticated, middleware.GetUserProfile, user_in_db, user_active, controllers.DeleteOrderItem(pool)) + router.DELETE("/order", user_authenticated, middleware.GetUserProfile, user_in_db, user_active, controllers.DeleteOrder(pool)) + router.DELETE("/item", user_authenticated, middleware.GetUserProfile, user_in_db, user_active, user_is_admin, controllers.DeleteItem(pool)) router.Run("localhost:8080") } diff --git a/api/queries/ItemQueries.go b/api/queries/ItemQueries.go index a9a59d9..aa7d02c 100644 --- a/api/queries/ItemQueries.go +++ b/api/queries/ItemQueries.go @@ -85,3 +85,13 @@ DELETE FROM order_item WHERE item_id = $1 AND order_id = $2; const SET_ITEM_IS_IN_SEASON = ` UPDATE item SET in_season = $1 WHERE id = $2; ` + +const GET_ORDER_MADE_DETAILS = ` +SELECT + id, + filled +FROM + order_record +WHERE + id = $1; +` diff --git a/api/queries/OrderQueries.go b/api/queries/OrderQueries.go index 6ccc74b..bec292e 100644 --- a/api/queries/OrderQueries.go +++ b/api/queries/OrderQueries.go @@ -61,7 +61,7 @@ WITH order_bill AS ( WHERE orec.user_id = $1 AND orec.orderer = $2 - AND orec.date_place = $3 + AND orec.date_placed = $3 GROUP BY orec.id ) totals ON orec.id = totals.id ) @@ -163,3 +163,19 @@ ORDER BY date_due DESC OFFSET $1 LIMIT $2; ` + +const UPDATE_ORDER_FILLED = `UPDATE order_record +SET filled = ( + SELECT order_filled + FROM order_record orec + INNER JOIN (SELECT + orec.id, + COALESCE(EVERY(made = quantity), false) AS order_filled + FROM + order_record orec + LEFT JOIN order_item oi ON oi.order_id = orec.id + GROUP BY + orec.id) orec_result ON orec.id = orec_result.id + AND orec.id = $1 +) WHERE order_record.id = $1 +` diff --git a/api/queries/UserQueries.go b/api/queries/UserQueries.go index df5bdea..932d653 100644 --- a/api/queries/UserQueries.go +++ b/api/queries/UserQueries.go @@ -31,6 +31,9 @@ FROM ordr_user INNER JOIN ordr_position ON job_position = ordr_position.id +WHERE + user_name LIKE '%' || $3 ||'%' + AND position_name LIKE '%' || $4 || '%' ORDER BY user_name OFFSET $1 LIMIT $2; @@ -45,7 +48,7 @@ SELECT is_admin::boolean FROM ordr_user - INNER JOIN ordr_position + LEFT JOIN ordr_position ON job_position = ordr_position.id AND ordr_user.sub_id = $1; ` diff --git a/api/utils/consts.go b/api/utils/consts.go index 9689a8f..6c0bbfa 100644 --- a/api/utils/consts.go +++ b/api/utils/consts.go @@ -64,11 +64,15 @@ func GetOrderTableQueryString(filter int64) string { ORDER BY date_due ` + order + ` OFFSET $1 LIMIT $2; - ` filter = filter & ^ASCEND_DATE_DUE - conditions := "" + conditions := ` + WHERE + orderer LIKE '%' || $3 || '%' + AND TO_CHAR(date_due, 'YYYY-MM-DD') LIKE '%' || $4 || '%' + AND TO_CHAR(date_placed, 'YYYY-MM-DD') LIKE '%' || $5 || '%' + ` if filter > 0 { if filter&FUTURE_FILTER > 0 { conditions += "AND date_due > now()\n" @@ -94,9 +98,6 @@ func GetOrderTableQueryString(filter int64) string { if filter&UNPAID_FILTER > 0 { conditions += "AND paid = FALSE\n" } - if len(conditions) > 0 { - conditions = "WHERE " + conditions[4:] - } } query_string := query_string_first_part + conditions + query_string_second_part diff --git a/db/schema initialization.sql b/db/schema initialization.sql index e72cdd4..39431e1 100644 --- a/db/schema initialization.sql +++ b/db/schema initialization.sql @@ -1,8 +1,15 @@ +CREATE TABLE IF NOT EXISTS ordr_position ( + id SERIAL NOT NULL PRIMARY KEY, + position_name TEXT NOT NULL +); + +INSERT INTO ordr_position VALUES (0, 'Unassigned'); + CREATE TABLE IF NOT EXISTS ordr_user ( id SERIAL NOT NULL PRIMARY KEY, sub_id TEXT UNIQUE NOT NULL, user_name TEXT NOT NULL, - position TEXT DEFAULT "", + position INTEGER NOT NULL DEFAULT 0 REFERENCES ordr_position ON DELETE SET NULL, active BOOLEAN NOT NULL DEFAULT TRUE, is_admin BOOLEAN NOT NULL DEFAULT FALSE ); @@ -25,7 +32,7 @@ CREATE TABLE IF NOT EXISTS item ( ); CREATE TABLE IF NOT EXISTS item_price_history ( - item_id INTEGER NOT NULL REFERENCES item(id), + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, price REAL NOT NULL, valid_from TIMESTAMP NOT NULL DEFAULT now(), valid_to TIMESTAMP, @@ -33,8 +40,8 @@ CREATE TABLE IF NOT EXISTS item_price_history ( ); CREATE TABLE IF NOT EXISTS order_item ( - item_id INTEGER NOT NULL REFERENCES item(id), - order_id INTEGER NOT NULL REFERENCES order_record(id), + item_id INTEGER NOT NULL REFERENCES item(id) ON DELETE CASCADE, + order_id INTEGER NOT NULL REFERENCES order_record(id) ON DELETE CASCADE, quantity INTEGER NOT NULL, made INTEGER NOT NULL DEFAULT 0, created_at TIMESTAMP NOT NULL DEFAULT now(), @@ -48,6 +55,6 @@ CREATE TABLE IF NOT EXISTS label ( ); CREATE TABLE IF NOT EXISTS order_label ( - order_id INTEGER NOT NULL REFERENCES order_record(id), - label_id INTEGER NOT NULL REFERENCES label(id) -); \ No newline at end of file + order_id INTEGER NOT NULL REFERENCES order_record(id) ON DELETE CASCADE, + label_id INTEGER NOT NULL REFERENCES label(id) ON DELETE CASCADE +);