mirror of
https://github.com/Mercantec-GHC/h4-projekt-gruppe-0-sm.git
synced 2025-04-27 16:24:07 +02:00
add json
This commit is contained in:
parent
86100a103a
commit
a82af5d6f6
@ -38,16 +38,18 @@ O_FILES = $(patsubst src/%.c,build/%.o,$(C_FILES))
|
||||
|
||||
CC = gcc
|
||||
|
||||
all: build_dir server
|
||||
all: server
|
||||
|
||||
server: $(O_FILES)
|
||||
$(CC) -o build/$@ $^ $(F_FLAGS) $(OPTIMIZATION) $(L_FLAGS)
|
||||
|
||||
build/%.o: src/%.c $(HEADERS)
|
||||
mkdir -p $(@D)
|
||||
$(CC) $< -c -o $@ $(C_FLAGS) $(OPTIMIZATION) $(F_FLAGS)
|
||||
|
||||
build_dir:
|
||||
mkdir -p build/
|
||||
|
||||
clean:
|
||||
rm -rf build/
|
||||
|
||||
drop_database:
|
||||
rm -rf database.db && sqlite3 database.db < prepare.sql
|
||||
|
||||
|
@ -6,22 +6,35 @@ CREATE TABLE IF NOT EXISTS users (
|
||||
balance_dkk_cent INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS coords (
|
||||
id INTEGER PRIMARY KEY,
|
||||
x INTEGER NOT NULL,
|
||||
y INTEGER NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS products (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
price_dkk_cent INTEGER NOT NULL
|
||||
price_dkk_cent INTEGER NOT NULL,
|
||||
description TEXT NOT NULL,
|
||||
coord INTEGER,
|
||||
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,
|
||||
|
||||
FOREIGN KEY(product) REFERENCES products(id)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS carts (
|
||||
id INTEGER PRIMARY KEY,
|
||||
user INTEGER NOT NULL,
|
||||
|
||||
FOREIGN KEY(user) REFERENCES users(id)
|
||||
);
|
||||
|
||||
@ -29,6 +42,7 @@ CREATE TABLE IF NOT EXISTS cart_items (
|
||||
id INTEGER PRIMARY KEY,
|
||||
cart INTEGER NOT NULL,
|
||||
amount INTEGER NOT NULL,
|
||||
|
||||
FOREIGN KEY(cart) REFERENCES carts(id)
|
||||
);
|
||||
|
||||
|
@ -81,7 +81,7 @@ const JsonValue* json_object_get(const JsonValue* value, const char* key)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void json_value_free(JsonValue* value)
|
||||
void json_free(JsonValue* value)
|
||||
{
|
||||
switch (value->type) {
|
||||
case JsonType_Error:
|
||||
@ -94,18 +94,28 @@ void json_value_free(JsonValue* value)
|
||||
break;
|
||||
case JsonType_Array:
|
||||
for (size_t i = 0; i < value->arr_val.size; ++i) {
|
||||
json_value_free(value->arr_val.data[i]);
|
||||
json_free(value->arr_val.data[i]);
|
||||
}
|
||||
arr_destroy(&value->arr_val);
|
||||
break;
|
||||
case JsonType_Object:
|
||||
for (size_t i = 0; i < value->obj_val.size; ++i) {
|
||||
free(value->obj_val.data[i].key);
|
||||
json_value_free(value->obj_val.data[i].val);
|
||||
json_free(value->obj_val.data[i].val);
|
||||
}
|
||||
obj_destroy(&value->obj_val);
|
||||
break;
|
||||
}
|
||||
free(value);
|
||||
}
|
||||
|
||||
JsonValue* json_parse(const char* text, size_t text_len)
|
||||
{
|
||||
JsonParser p;
|
||||
json_parser_construct(&p, text, text_len);
|
||||
JsonValue* json = json_parser_parse(&p);
|
||||
json_parser_destroy(&p);
|
||||
return json;
|
||||
}
|
||||
|
||||
#define TOK_EOF '\0'
|
||||
|
@ -26,7 +26,8 @@ const JsonValue* json_array_get(const JsonValue* value, size_t idx);
|
||||
bool json_object_has(const JsonValue* value, const char* key);
|
||||
const JsonValue* json_object_get(const JsonValue* value, const char* key);
|
||||
|
||||
void json_value_free(JsonValue* value);
|
||||
void json_free(JsonValue* value);
|
||||
JsonValue* json_parse(const char* text, size_t text_len);
|
||||
|
||||
typedef struct {
|
||||
const char* text;
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "http_server.h"
|
||||
#include "json.h"
|
||||
#include "models.h"
|
||||
#include "models_json.h"
|
||||
#include "str_util.h"
|
||||
#include <sqlite3.h>
|
||||
#include <stdio.h>
|
||||
@ -61,7 +63,7 @@ void route_post_set_number(HttpCtx* ctx)
|
||||
RESPOND_JSON(ctx, 200, "{\"ok\": true}\r\n");
|
||||
|
||||
l0_return:
|
||||
json_value_free(body);
|
||||
json_free(body);
|
||||
}
|
||||
|
||||
static inline void insert_test_user(sqlite3* db)
|
||||
@ -79,7 +81,7 @@ static inline void insert_test_user(sqlite3* db)
|
||||
|
||||
sqlite3_bind_text(stmt, 1, email, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(stmt, 2, password_hash_str, -1, SQLITE_STATIC);
|
||||
sqlite3_bind_int(stmt, 3, 123);
|
||||
sqlite3_bind_int64(stmt, 3, 123);
|
||||
|
||||
int res = sqlite3_step(stmt);
|
||||
if (res != SQLITE_DONE) {
|
||||
@ -94,6 +96,35 @@ HttpServer* server;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
||||
User user = {
|
||||
.id = 12,
|
||||
.email = str_dup("test@mail.dk"),
|
||||
.password_hash = str_dup("hawd"),
|
||||
.balance_dkk_cent = 321,
|
||||
};
|
||||
|
||||
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) {
|
||||
|
183
backend/src/models.c
Normal file
183
backend/src/models.c
Normal file
@ -0,0 +1,183 @@
|
||||
#include "models.h"
|
||||
#include "json.h"
|
||||
#include "str_util.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void user_free(User* m)
|
||||
{
|
||||
free(m->email);
|
||||
free(m->password_hash);
|
||||
}
|
||||
|
||||
void coord_free(Coord* m)
|
||||
{
|
||||
(void)m;
|
||||
}
|
||||
|
||||
void product_free(Product* m)
|
||||
{
|
||||
free(m->name);
|
||||
free(m->barcode);
|
||||
}
|
||||
|
||||
void product_price_free(ProductPrice* m)
|
||||
{
|
||||
(void)m;
|
||||
}
|
||||
|
||||
void cart_free(Cart* m)
|
||||
{
|
||||
(void)m;
|
||||
}
|
||||
|
||||
void cart_item_free(CartItem* m)
|
||||
{
|
||||
(void)m;
|
||||
}
|
||||
|
||||
char* user_to_json_string(const User* m)
|
||||
{
|
||||
String string;
|
||||
string_construct(&string);
|
||||
string_pushf(&string,
|
||||
"{"
|
||||
"\"id\":%ld,"
|
||||
"\"email\":\"%s\","
|
||||
"\"password_hash\":\"%s\","
|
||||
"\"balance_dkk_cent\":%ld"
|
||||
"}",
|
||||
m->id, m->email, m->password_hash, m->balance_dkk_cent);
|
||||
|
||||
char* result = string_copy(&string);
|
||||
string_destroy(&string);
|
||||
return result;
|
||||
}
|
||||
|
||||
char* coord_to_json_string(const Coord* m)
|
||||
{
|
||||
String string;
|
||||
string_construct(&string);
|
||||
string_pushf(&string,
|
||||
"{"
|
||||
"\"id\":%ld,"
|
||||
"\"x\":%ld,"
|
||||
"\"y\":%ld"
|
||||
"}",
|
||||
m->id, m->x, m->y);
|
||||
|
||||
char* result = string_copy(&string);
|
||||
string_destroy(&string);
|
||||
return result;
|
||||
}
|
||||
|
||||
char* product_to_json_string(const Product* m)
|
||||
{
|
||||
String string;
|
||||
string_construct(&string);
|
||||
string_pushf(&string,
|
||||
"{"
|
||||
"\"id\":%ld,"
|
||||
"\"name\":\"%s\","
|
||||
"\"price_dkk_cent\":%ld,"
|
||||
"\"coord_id\":%ld,"
|
||||
"\"barcode\":\"%s\""
|
||||
"}",
|
||||
m->id, m->name, m->price_dkk_cent, m->coord_id, m->barcode);
|
||||
|
||||
char* result = string_copy(&string);
|
||||
string_destroy(&string);
|
||||
return result;
|
||||
}
|
||||
|
||||
char* product_price_to_json_string(const ProductPrice* m)
|
||||
{
|
||||
String string;
|
||||
string_construct(&string);
|
||||
string_pushf(&string,
|
||||
"{"
|
||||
"\"id\":%ld,"
|
||||
"\"product_id\":%ld,"
|
||||
"\"price_dkk_cent\":%ld"
|
||||
"}",
|
||||
m->id, m->product_id, m->price_dkk_cent);
|
||||
|
||||
char* result = string_copy(&string);
|
||||
string_destroy(&string);
|
||||
return result;
|
||||
}
|
||||
|
||||
char* cart_to_json_string(const Cart* m)
|
||||
{
|
||||
String string;
|
||||
string_construct(&string);
|
||||
string_pushf(&string,
|
||||
"{"
|
||||
"\"id\":%ld,"
|
||||
"\"user_id\":%ld"
|
||||
"}",
|
||||
m->id, m->user_id);
|
||||
|
||||
char* result = string_copy(&string);
|
||||
string_destroy(&string);
|
||||
return result;
|
||||
}
|
||||
|
||||
char* cart_item_to_json_string(const CartItem* m)
|
||||
{
|
||||
String string;
|
||||
string_construct(&string);
|
||||
string_pushf(&string,
|
||||
"{"
|
||||
"\"id\":%ld,"
|
||||
"\"cart_id\":%ld,"
|
||||
"\"amount\":%ld"
|
||||
"}",
|
||||
m->id, m->cart_id, m->amount);
|
||||
|
||||
char* result = string_copy(&string);
|
||||
string_destroy(&string);
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char* key;
|
||||
JsonType type;
|
||||
} ObjField;
|
||||
|
||||
static inline bool obj_conforms(
|
||||
const JsonValue* val, const ObjField* fields, size_t fields_size)
|
||||
{
|
||||
if (!json_is(val, JsonType_Object)) {
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < fields_size; ++i) {
|
||||
if (!json_object_has(val, fields[i].key)) {
|
||||
return false;
|
||||
}
|
||||
if (!json_is(json_object_get(val, fields[i].key), fields[i].type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int user_from_json(User* m, const JsonValue* json)
|
||||
{
|
||||
ObjField fields[] = {
|
||||
{ "id", JsonType_Number },
|
||||
{ "email", JsonType_String },
|
||||
{ "password_hash", JsonType_String },
|
||||
{ "balance_dkk_cent", JsonType_Number },
|
||||
};
|
||||
if (!obj_conforms(json, fields, sizeof(fields) / sizeof(fields[0])))
|
||||
return -1;
|
||||
*m = (User) {
|
||||
.id = json_int(json_object_get(json, "id")),
|
||||
.email = str_dup(json_string(json_object_get(json, "email"))),
|
||||
.password_hash
|
||||
= str_dup(json_string(json_object_get(json, "password_hash"))),
|
||||
.balance_dkk_cent = json_int(json_object_get(json, "balance_dkk_cent")),
|
||||
};
|
||||
return 0;
|
||||
}
|
48
backend/src/models.h
Normal file
48
backend/src/models.h
Normal file
@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
int64_t id;
|
||||
char* email;
|
||||
char* password_hash;
|
||||
int64_t balance_dkk_cent;
|
||||
} User;
|
||||
|
||||
typedef struct {
|
||||
int64_t id;
|
||||
int64_t x;
|
||||
int64_t y;
|
||||
} Coord;
|
||||
|
||||
typedef struct {
|
||||
int64_t id;
|
||||
char* name;
|
||||
int64_t price_dkk_cent;
|
||||
int64_t coord_id;
|
||||
char* barcode;
|
||||
} Product;
|
||||
|
||||
typedef struct {
|
||||
int64_t id;
|
||||
int64_t product_id;
|
||||
int64_t price_dkk_cent;
|
||||
} ProductPrice;
|
||||
|
||||
typedef struct {
|
||||
int64_t id;
|
||||
int64_t user_id;
|
||||
} Cart;
|
||||
|
||||
typedef struct {
|
||||
int64_t id;
|
||||
int64_t cart_id;
|
||||
int64_t amount;
|
||||
} CartItem;
|
||||
|
||||
void user_free(User* model);
|
||||
void coord_free(Coord* model);
|
||||
void product_free(Product* model);
|
||||
void product_price_free(ProductPrice* model);
|
||||
void cart_free(Cart* model);
|
||||
void cart_item_free(CartItem* model);
|
13
backend/src/models_json.h
Normal file
13
backend/src/models_json.h
Normal file
@ -0,0 +1,13 @@
|
||||
#include "json.h"
|
||||
#include "models.h"
|
||||
|
||||
#define DEFINE_MODEL_JSON(TYPE, PREFIX) \
|
||||
char* PREFIX##_to_json_string(const TYPE* model); \
|
||||
int PREFIX##_from_json(TYPE* model, const JsonValue* json);
|
||||
|
||||
DEFINE_MODEL_JSON(User, user)
|
||||
DEFINE_MODEL_JSON(Coord, coord)
|
||||
DEFINE_MODEL_JSON(Product, product)
|
||||
DEFINE_MODEL_JSON(ProductPrice, product_price)
|
||||
DEFINE_MODEL_JSON(Cart, cart)
|
||||
DEFINE_MODEL_JSON(CartItem, cart_item)
|
16
backend/src/models_sqlite.h
Normal file
16
backend/src/models_sqlite.h
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "models.h"
|
||||
#include <sqlite3.h>
|
||||
|
||||
int user_sqlite_from_id(User* model, sqlite3* db, int64_t id);
|
||||
|
||||
int coord_sqlite_from(Coord* model, sqlite3* db);
|
||||
|
||||
int product_sqlite_from(Product* model, sqlite3_stmt* stmt);
|
||||
|
||||
int product_price_sqlite_from(ProductPrice* model, sqlite3_stmt* stmt);
|
||||
|
||||
int cart_sqlite_from(Cart* model, sqlite3_stmt* stmt);
|
||||
|
||||
int cart_item_sqlite_from(CartItem* model, sqlite3_stmt* stmt);
|
@ -6,6 +6,13 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
char* str_dup(const char* str)
|
||||
{
|
||||
char* clone = calloc(strlen(str) + 1, sizeof(char));
|
||||
strcpy(clone, str);
|
||||
return clone;
|
||||
}
|
||||
|
||||
StrSplitter str_split(const char* text, size_t text_len, const char* split)
|
||||
{
|
||||
return (StrSplitter) {
|
||||
@ -41,6 +48,19 @@ void string_push_str(String* string, const char* str)
|
||||
}
|
||||
}
|
||||
|
||||
void string_push_fmt_va(String* string, const char* fmt, ...)
|
||||
{
|
||||
va_list args1;
|
||||
va_start(args1, fmt);
|
||||
va_list args2;
|
||||
va_copy(args2, args1);
|
||||
char buf[1 + vsnprintf(NULL, 0, fmt, args1)];
|
||||
va_end(args1);
|
||||
vsnprintf(buf, sizeof buf, fmt, args2);
|
||||
va_end(args2);
|
||||
string_push_str(string, buf);
|
||||
}
|
||||
|
||||
char* string_copy(const String* string)
|
||||
{
|
||||
char* copy = malloc(string->size + 1);
|
||||
|
@ -5,6 +5,8 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
char* str_dup(const char* str);
|
||||
|
||||
typedef struct {
|
||||
const char* ptr;
|
||||
size_t len;
|
||||
@ -24,8 +26,11 @@ StrSlice strsplit_next(StrSplitter* splitter);
|
||||
DEFINE_VEC(char, String, string, 8)
|
||||
|
||||
void string_push_str(String* string, const char* str);
|
||||
void string_push_fmt_va(String* string, const char* fmt, ...);
|
||||
char* string_copy(const String* string);
|
||||
|
||||
#define string_pushf(STRING, ...) string_push_fmt_va(STRING, __VA_ARGS__)
|
||||
|
||||
DEFINE_VEC(char*, RawStrVec, rawstr_vec, 8)
|
||||
|
||||
#define MAX_HASH_INPUT_LEN 256
|
||||
|
Loading…
x
Reference in New Issue
Block a user