mirror of
https://github.com/Mercantec-GHC/h4-projekt-gruppe-0-sm.git
synced 2025-04-28 08:44:06 +02:00
get all products
This commit is contained in:
parent
fa870b6988
commit
2ce894d756
@ -1,49 +1,54 @@
|
|||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS users (
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
id INTEGER PRIMARY KEY,
|
id INT PRIMARY KEY,
|
||||||
email TEXT NOT NULL,
|
email TEXT NOT NULL,
|
||||||
password_hash 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 (
|
CREATE TABLE IF NOT EXISTS coords (
|
||||||
id INTEGER PRIMARY KEY,
|
id INT PRIMARY KEY,
|
||||||
x INTEGER NOT NULL,
|
x INT NOT NULL,
|
||||||
y INTEGER NOT NULL
|
y INT NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS products (
|
CREATE TABLE IF NOT EXISTS products (
|
||||||
id INTEGER PRIMARY KEY,
|
id INT PRIMARY KEY,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
price_dkk_cent INTEGER NOT NULL,
|
price_dkk_cent INT NOT NULL,
|
||||||
description TEXT NOT NULL,
|
description TEXT NOT NULL,
|
||||||
coord INTEGER,
|
coord INT,
|
||||||
barcode TEXT,
|
barcode TEXT,
|
||||||
|
|
||||||
FOREIGN KEY(coord) REFERENCES coords(id)
|
FOREIGN KEY(coord) REFERENCES coords(id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS product_prices (
|
CREATE TABLE IF NOT EXISTS product_prices (
|
||||||
id INTEGER PRIMARY KEY,
|
id INT PRIMARY KEY,
|
||||||
product INTEGER NOT NULL,
|
product INT NOT NULL,
|
||||||
price_dkk_cent INTEGER NOT NULL,
|
price_dkk_cent INT NOT NULL,
|
||||||
|
|
||||||
FOREIGN KEY(product) REFERENCES products(id)
|
FOREIGN KEY(product) REFERENCES products(id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS carts (
|
CREATE TABLE IF NOT EXISTS carts (
|
||||||
id INTEGER PRIMARY KEY,
|
id INT PRIMARY KEY,
|
||||||
user INTEGER NOT NULL,
|
user INT NOT NULL,
|
||||||
|
|
||||||
FOREIGN KEY(user) REFERENCES users(id)
|
FOREIGN KEY(user) REFERENCES users(id)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS cart_items (
|
CREATE TABLE IF NOT EXISTS cart_items (
|
||||||
id INTEGER PRIMARY KEY,
|
id INT PRIMARY KEY,
|
||||||
cart INTEGER NOT NULL,
|
cart INT NOT NULL,
|
||||||
amount INTEGER NOT NULL,
|
amount INT NOT NULL,
|
||||||
|
|
||||||
FOREIGN KEY(cart) REFERENCES carts(id)
|
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 "http_server.h"
|
||||||
#include "json.h"
|
#include "json.h"
|
||||||
#include "models.h"
|
#include "models.h"
|
||||||
@ -7,30 +10,6 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.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)
|
void route_get_index(HttpCtx* ctx)
|
||||||
{
|
{
|
||||||
Cx* cx = http_ctx_user_ctx(ctx);
|
Cx* cx = http_ctx_user_ctx(ctx);
|
||||||
@ -66,76 +45,17 @@ l0_return:
|
|||||||
json_free(body);
|
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;
|
HttpServer* server;
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
|
Db* db = db_sqlite_new();
|
||||||
|
|
||||||
User user = {
|
Cx cx = {
|
||||||
.id = 12,
|
.number = 1,
|
||||||
.email = str_dup("test@mail.dk"),
|
.db = db,
|
||||||
.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) {
|
|
||||||
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) {
|
server = http_server_new((HttpServerOpts) {
|
||||||
.port = 8080,
|
.port = 8080,
|
||||||
.workers_amount = 8,
|
.workers_amount = 8,
|
||||||
@ -145,6 +65,9 @@ int main(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
http_server_set_user_ctx(server, &cx);
|
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_get(server, "/", route_get_index);
|
||||||
http_server_post(server, "/set_number", route_post_set_number);
|
http_server_post(server, "/set_number", route_post_set_number);
|
||||||
|
|
||||||
@ -152,5 +75,5 @@ int main(void)
|
|||||||
http_server_listen(server);
|
http_server_listen(server);
|
||||||
|
|
||||||
http_server_free(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) {
|
for (size_t i = 0; i < strlen(str); ++i) {
|
||||||
string_push(string, str[i]);
|
string_push(string, str[i]);
|
||||||
}
|
}
|
||||||
|
string->data[string->size] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
void string_push_fmt_va(String* string, const char* fmt, ...)
|
void string_push_fmt_va(String* string, const char* fmt, ...)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user