mirror of
https://github.com/Mercantec-GHC/h4-projekt-gruppe-0-sm.git
synced 2025-04-27 16:24:07 +02:00
get all products
This commit is contained in:
parent
fa870b6988
commit
2ce894d756
@ -1,49 +1,54 @@
|
||||
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id INTEGER PRIMARY KEY,
|
||||
id INT PRIMARY KEY,
|
||||
email TEXT NOT NULL,
|
||||
password_hash TEXT NOT NULL,
|
||||
balance_dkk_cent INTEGER NOT NULL
|
||||
balance_dkk_cent INT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS coords (
|
||||
id INTEGER PRIMARY KEY,
|
||||
x INTEGER NOT NULL,
|
||||
y INTEGER NOT NULL
|
||||
id INT PRIMARY KEY,
|
||||
x INT NOT NULL,
|
||||
y INT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS products (
|
||||
id INTEGER PRIMARY KEY,
|
||||
id INT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
price_dkk_cent INTEGER NOT NULL,
|
||||
price_dkk_cent INT NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
coord INTEGER,
|
||||
coord INT,
|
||||
barcode TEXT,
|
||||
|
||||
FOREIGN KEY(coord) REFERENCES coords(id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS product_prices (
|
||||
id INTEGER PRIMARY KEY,
|
||||
product INTEGER NOT NULL,
|
||||
price_dkk_cent INTEGER NOT NULL,
|
||||
id INT PRIMARY KEY,
|
||||
product INT NOT NULL,
|
||||
price_dkk_cent INT NOT NULL,
|
||||
|
||||
FOREIGN KEY(product) REFERENCES products(id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS carts (
|
||||
id INTEGER PRIMARY KEY,
|
||||
user INTEGER NOT NULL,
|
||||
id INT PRIMARY KEY,
|
||||
user INT NOT NULL,
|
||||
|
||||
FOREIGN KEY(user) REFERENCES users(id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS cart_items (
|
||||
id INTEGER PRIMARY KEY,
|
||||
cart INTEGER NOT NULL,
|
||||
amount INTEGER NOT NULL,
|
||||
id INT PRIMARY KEY,
|
||||
cart INT NOT NULL,
|
||||
amount INT NOT NULL,
|
||||
|
||||
FOREIGN KEY(cart) REFERENCES carts(id)
|
||||
);
|
||||
|
||||
|
||||
|
||||
INSERT OR REPLACE INTO users VALUES(1,'test@email.com','d980840fcb82970ab86656feebdccdd288be0e9b05f14e712b59529a2868fee3d980840fcb82970ab86656feebdccdd288be0e9b05f14e712b59529a2868fee3',10000);
|
||||
|
||||
INSERT OR REPLACE INTO products VALUES(1,'Letmælk',1195,'Mælk fra ko',NULL,NULL);
|
||||
INSERT OR REPLACE INTO products VALUES(2,'Smør',2000,'Smør fra mejeri',NULL,NULL);
|
||||
|
30
backend/src/controllers.h
Normal file
30
backend/src/controllers.h
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include "db.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
int number;
|
||||
Db* db;
|
||||
} Cx;
|
||||
|
||||
#define RESPOND(HTTP_CTX, STATUS, MIME_TYPE, ...) \
|
||||
{ \
|
||||
HttpCtx* _ctx = (HTTP_CTX); \
|
||||
char _body[512]; \
|
||||
snprintf(_body, 512 - 1, __VA_ARGS__); \
|
||||
\
|
||||
char content_length[24] = { 0 }; \
|
||||
snprintf(content_length, 24 - 1, "%ld", strlen(_body)); \
|
||||
\
|
||||
http_ctx_res_headers_set(_ctx, "Content-Type", MIME_TYPE); \
|
||||
http_ctx_res_headers_set(_ctx, "Content-Length", content_length); \
|
||||
\
|
||||
http_ctx_respond(_ctx, (STATUS), _body); \
|
||||
}
|
||||
|
||||
#define RESPOND_HTML(HTTP_CTX, STATUS, ...) \
|
||||
RESPOND(HTTP_CTX, STATUS, "text/html", __VA_ARGS__)
|
||||
#define RESPOND_JSON(HTTP_CTX, STATUS, ...) \
|
||||
RESPOND(HTTP_CTX, STATUS, "application/json", __VA_ARGS__)
|
37
backend/src/controllers/products.c
Normal file
37
backend/src/controllers/products.c
Normal file
@ -0,0 +1,37 @@
|
||||
#include "products.h"
|
||||
#include "../controllers.h"
|
||||
#include "../http_server.h"
|
||||
#include "../models_json.h"
|
||||
#include "../str_util.h"
|
||||
|
||||
void route_get_products_all(HttpCtx* ctx)
|
||||
{
|
||||
Cx* cx = http_ctx_user_ctx(ctx);
|
||||
|
||||
ProductVec products;
|
||||
product_vec_construct(&products);
|
||||
|
||||
DbRes db_res = db_product_all_fill(cx->db, &products);
|
||||
if (db_res != DbRes_Ok) {
|
||||
RESPOND_JSON(ctx, 500, "{\"ok\":false,\"msg\":\"db error\"}");
|
||||
return;
|
||||
}
|
||||
|
||||
String res;
|
||||
string_construct(&res);
|
||||
|
||||
string_push_str(&res, "{\"ok\":true,\"products\":[");
|
||||
for (size_t i = 0; i < products.size; ++i) {
|
||||
if (i != 0) {
|
||||
string_push_str(&res, ",");
|
||||
}
|
||||
char* json = product_to_json_string(&products.data[i]);
|
||||
string_push_str(&res, json);
|
||||
free(json);
|
||||
}
|
||||
string_push_str(&res, "]}");
|
||||
|
||||
product_vec_destroy(&products);
|
||||
RESPOND_JSON(ctx, 200, "%s", res.data);
|
||||
string_destroy(&res);
|
||||
}
|
6
backend/src/controllers/products.h
Normal file
6
backend/src/controllers/products.h
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../controllers.h"
|
||||
#include "../http_server.h"
|
||||
|
||||
void route_get_products_all(HttpCtx* ctx);
|
20
backend/src/db.h
Normal file
20
backend/src/db.h
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "collection.h"
|
||||
#include "models.h"
|
||||
|
||||
DEFINE_VEC(Product, ProductVec, product_vec, 32)
|
||||
|
||||
typedef enum {
|
||||
DbRes_Ok,
|
||||
DbRes_NotFound,
|
||||
DbRes_Error,
|
||||
} DbRes;
|
||||
|
||||
typedef struct Db Db;
|
||||
|
||||
/// `user.id` field is ignored.
|
||||
DbRes db_user_insert(Db* db, User* user);
|
||||
DbRes db_user_from_id(Db* db, User* user, int64_t id);
|
||||
|
||||
DbRes db_product_all_fill(Db* db, ProductVec* vec);
|
174
backend/src/db_sqlite.c
Normal file
174
backend/src/db_sqlite.c
Normal file
@ -0,0 +1,174 @@
|
||||
#include "db_sqlite.h"
|
||||
#include "db.h"
|
||||
#include "str_util.h"
|
||||
#include <sqlite3.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static inline char* get_str_safe(sqlite3_stmt* stmt, int col)
|
||||
{
|
||||
const char* val = (const char*)sqlite3_column_text(stmt, col);
|
||||
if (!val)
|
||||
return str_dup("NULL");
|
||||
return str_dup((const char*)val);
|
||||
}
|
||||
|
||||
#define GET_INT(COL) sqlite3_column_int64(stmt, COL)
|
||||
#define GET_STR(COL) get_str_safe(stmt, COL)
|
||||
|
||||
Db* db_sqlite_new(void)
|
||||
{
|
||||
Db* db = malloc(sizeof(Db));
|
||||
|
||||
sqlite3* connection;
|
||||
int res = sqlite3_open("database.db", &connection);
|
||||
if (res != SQLITE_OK) {
|
||||
fprintf(stderr, "error: could not open sqlite 'database.db'\n");
|
||||
return NULL;
|
||||
}
|
||||
sqlite3_close(connection);
|
||||
|
||||
return db;
|
||||
}
|
||||
|
||||
void db_sqlite_free(Db* db)
|
||||
{
|
||||
// sqlite3_close(db->connection);
|
||||
free(db);
|
||||
}
|
||||
|
||||
static inline DbRes connect(sqlite3** connection)
|
||||
{
|
||||
int res = sqlite3_open("database.db", connection);
|
||||
if (res != SQLITE_OK) {
|
||||
fprintf(stderr, "error: could not open sqlite 'database.db'\n %s\n",
|
||||
sqlite3_errmsg(*connection));
|
||||
return DbRes_Error;
|
||||
}
|
||||
return DbRes_Ok;
|
||||
}
|
||||
|
||||
static inline void disconnect(sqlite3* connection)
|
||||
{
|
||||
sqlite3_close(connection);
|
||||
}
|
||||
|
||||
#define CONNECT \
|
||||
{ \
|
||||
if (connect(&connection) != DbRes_Ok) { \
|
||||
return DbRes_Error; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define DISCONNECT \
|
||||
{ \
|
||||
disconnect(connection); \
|
||||
}
|
||||
|
||||
DbRes db_user_insert(Db* db, User* user)
|
||||
{
|
||||
sqlite3* connection;
|
||||
CONNECT;
|
||||
DbRes res;
|
||||
|
||||
sqlite3_stmt* stmt;
|
||||
sqlite3_prepare_v2(connection,
|
||||
"INSERT INTO users (email, password_hash, balance_dkk_cent) "
|
||||
"VALUES (?, ?, ?)",
|
||||
-1, &stmt, NULL);
|
||||
|
||||
sqlite3_bind_text(stmt, 1, user->email, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(stmt, 2, user->password_hash, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_int64(stmt, 3, user->balance_dkk_cent);
|
||||
|
||||
int step_res = sqlite3_step(stmt);
|
||||
if (step_res != SQLITE_DONE) {
|
||||
fprintf(stderr, "error: %s\n", sqlite3_errmsg(connection));
|
||||
res = DbRes_Error;
|
||||
goto l0_return;
|
||||
}
|
||||
|
||||
res = DbRes_Ok;
|
||||
l0_return:
|
||||
if (stmt)
|
||||
sqlite3_finalize(stmt);
|
||||
DISCONNECT;
|
||||
return res;
|
||||
}
|
||||
|
||||
DbRes db_user_from_id(Db* db, User* user, int64_t id)
|
||||
{
|
||||
sqlite3* connection;
|
||||
CONNECT;
|
||||
DbRes res;
|
||||
|
||||
sqlite3_stmt* stmt;
|
||||
sqlite3_prepare_v2(connection,
|
||||
"SELECT id, email, password_hash, balance_dkk_cent"
|
||||
"FROM users WHERE id = ?",
|
||||
-1, &stmt, NULL);
|
||||
sqlite3_bind_int64(stmt, 1, id);
|
||||
|
||||
int step_res = sqlite3_step(stmt);
|
||||
if (step_res == SQLITE_DONE) {
|
||||
res = DbRes_NotFound;
|
||||
goto l0_return;
|
||||
} else if (step_res != SQLITE_ROW) {
|
||||
fprintf(stderr, "error: %s\n", sqlite3_errmsg(connection));
|
||||
res = DbRes_Error;
|
||||
goto l0_return;
|
||||
}
|
||||
*user = (User) {
|
||||
.id = GET_INT(0),
|
||||
.email = GET_STR(1),
|
||||
.password_hash = GET_STR(2),
|
||||
.balance_dkk_cent = GET_INT(3),
|
||||
};
|
||||
|
||||
res = DbRes_Ok;
|
||||
l0_return:
|
||||
if (stmt)
|
||||
sqlite3_finalize(stmt);
|
||||
DISCONNECT;
|
||||
return res;
|
||||
}
|
||||
|
||||
DbRes db_product_all_fill(Db* db, ProductVec* vec)
|
||||
{
|
||||
sqlite3* connection;
|
||||
CONNECT;
|
||||
DbRes res;
|
||||
int sqlite_res;
|
||||
|
||||
sqlite3_stmt* stmt;
|
||||
sqlite_res = sqlite3_prepare_v2(connection,
|
||||
"SELECT id, name, price_dkk_cent, coord, barcode FROM products", -1,
|
||||
&stmt, NULL);
|
||||
if (sqlite_res != SQLITE_OK) {
|
||||
fprintf(stderr, "error: %s\n", sqlite3_errmsg(connection));
|
||||
res = DbRes_Error;
|
||||
goto l0_return;
|
||||
}
|
||||
|
||||
while ((sqlite_res = sqlite3_step(stmt)) == SQLITE_ROW) {
|
||||
Product product = {
|
||||
.id = GET_INT(0),
|
||||
.name = GET_STR(1),
|
||||
.price_dkk_cent = GET_INT(2),
|
||||
.coord_id = GET_INT(3),
|
||||
.barcode = GET_STR(4),
|
||||
};
|
||||
product_vec_push(vec, product);
|
||||
}
|
||||
if (sqlite_res != SQLITE_DONE) {
|
||||
fprintf(stderr, "error: %s\n", sqlite3_errmsg(connection));
|
||||
res = DbRes_Error;
|
||||
goto l0_return;
|
||||
}
|
||||
|
||||
res = DbRes_Ok;
|
||||
l0_return:
|
||||
if (stmt)
|
||||
sqlite3_finalize(stmt);
|
||||
DISCONNECT;
|
||||
return res;
|
||||
}
|
11
backend/src/db_sqlite.h
Normal file
11
backend/src/db_sqlite.h
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "db.h"
|
||||
#include <sqlite3.h>
|
||||
|
||||
struct Db {
|
||||
int empty;
|
||||
};
|
||||
|
||||
Db* db_sqlite_new(void);
|
||||
void db_sqlite_free(Db* db);
|
@ -1,3 +1,6 @@
|
||||
#include "controllers.h"
|
||||
#include "controllers/products.h"
|
||||
#include "db_sqlite.h"
|
||||
#include "http_server.h"
|
||||
#include "json.h"
|
||||
#include "models.h"
|
||||
@ -7,30 +10,6 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct {
|
||||
int number;
|
||||
} Cx;
|
||||
|
||||
#define RESPOND(HTTP_CTX, STATUS, MIME_TYPE, ...) \
|
||||
{ \
|
||||
HttpCtx* _ctx = (HTTP_CTX); \
|
||||
char _body[512]; \
|
||||
snprintf(_body, 512 - 1, __VA_ARGS__); \
|
||||
\
|
||||
char content_length[24] = { 0 }; \
|
||||
snprintf(content_length, 24 - 1, "%ld", strlen(_body)); \
|
||||
\
|
||||
http_ctx_res_headers_set(_ctx, "Content-Type", MIME_TYPE); \
|
||||
http_ctx_res_headers_set(_ctx, "Content-Length", content_length); \
|
||||
\
|
||||
http_ctx_respond(_ctx, (STATUS), _body); \
|
||||
}
|
||||
|
||||
#define RESPOND_HTML(HTTP_CTX, STATUS, ...) \
|
||||
RESPOND(HTTP_CTX, STATUS, "text/html", __VA_ARGS__)
|
||||
#define RESPOND_JSON(HTTP_CTX, STATUS, ...) \
|
||||
RESPOND(HTTP_CTX, STATUS, "application/json", __VA_ARGS__)
|
||||
|
||||
void route_get_index(HttpCtx* ctx)
|
||||
{
|
||||
Cx* cx = http_ctx_user_ctx(ctx);
|
||||
@ -66,76 +45,17 @@ l0_return:
|
||||
json_free(body);
|
||||
}
|
||||
|
||||
static inline void insert_test_user(sqlite3* db)
|
||||
{
|
||||
sqlite3_stmt* stmt;
|
||||
sqlite3_prepare_v2(db,
|
||||
"INSERT INTO users (email, password_hash, balance_dkk_cent) "
|
||||
"VALUES (?, ?, ?)",
|
||||
-1, &stmt, NULL);
|
||||
|
||||
char email[] = "testuser@email.com";
|
||||
char password[] = "1234";
|
||||
StrHash password_hash = str_hash(password);
|
||||
char* password_hash_str = str_hash_to_string(password_hash);
|
||||
|
||||
sqlite3_bind_text(stmt, 1, email, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(stmt, 2, password_hash_str, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_int64(stmt, 3, 123);
|
||||
|
||||
int res = sqlite3_step(stmt);
|
||||
if (res != SQLITE_DONE) {
|
||||
fprintf(stderr, "error: could not insert test user: %s\n",
|
||||
sqlite3_errmsg(db));
|
||||
}
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
|
||||
HttpServer* server;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Db* db = db_sqlite_new();
|
||||
|
||||
User user = {
|
||||
.id = 12,
|
||||
.email = str_dup("test@mail.dk"),
|
||||
.password_hash = str_dup("hawd"),
|
||||
.balance_dkk_cent = 321,
|
||||
Cx cx = {
|
||||
.number = 1,
|
||||
.db = db,
|
||||
};
|
||||
|
||||
char* str = user_to_json_string(&user);
|
||||
printf("user = '%s'\n", str);
|
||||
|
||||
User user2;
|
||||
|
||||
JsonValue* json = json_parse(str, strlen(str));
|
||||
|
||||
user_from_json(&user2, json);
|
||||
|
||||
char* str2 = user_to_json_string(&user2);
|
||||
printf("user2 = '%s'\n", str2);
|
||||
|
||||
user_free(&user);
|
||||
user_free(&user2);
|
||||
|
||||
json_free(json);
|
||||
free(str);
|
||||
free(str2);
|
||||
|
||||
return 0;
|
||||
|
||||
sqlite3* db;
|
||||
int res = sqlite3_open("database.db", &db);
|
||||
if (res != SQLITE_OK) {
|
||||
fprintf(stderr, "error: could not open sqlite 'database.db'\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
insert_test_user(db);
|
||||
|
||||
Cx cx = { .number = 1 };
|
||||
|
||||
server = http_server_new((HttpServerOpts) {
|
||||
.port = 8080,
|
||||
.workers_amount = 8,
|
||||
@ -145,6 +65,9 @@ int main(void)
|
||||
}
|
||||
|
||||
http_server_set_user_ctx(server, &cx);
|
||||
|
||||
http_server_get(server, "/products/all", route_get_products_all);
|
||||
|
||||
http_server_get(server, "/", route_get_index);
|
||||
http_server_post(server, "/set_number", route_post_set_number);
|
||||
|
||||
@ -152,5 +75,5 @@ int main(void)
|
||||
http_server_listen(server);
|
||||
|
||||
http_server_free(server);
|
||||
sqlite3_close(db);
|
||||
db_sqlite_free(db);
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ void string_push_str(String* string, const char* str)
|
||||
for (size_t i = 0; i < strlen(str); ++i) {
|
||||
string_push(string, str[i]);
|
||||
}
|
||||
string->data[string->size] = '\0';
|
||||
}
|
||||
|
||||
void string_push_fmt_va(String* string, const char* fmt, ...)
|
||||
|
Loading…
x
Reference in New Issue
Block a user