code: dbal,frontends,cpp (3 files)

This commit is contained in:
2025-12-26 05:48:35 +00:00
parent 375a5f52f0
commit b35becffb2
3 changed files with 76 additions and 6 deletions

View File

@@ -0,0 +1,66 @@
#include "server_helpers/serialization.hpp"
#include <chrono>
#include <json/json.h>
namespace dbal {
namespace daemon {
long long timestamp_to_epoch_ms(const Timestamp& timestamp) {
return std::chrono::duration_cast<std::chrono::milliseconds>(timestamp.time_since_epoch()).count();
}
Json::Value user_to_json(const User& user) {
Json::Value value(Json::objectValue);
value["id"] = user.id;
value["username"] = user.username;
value["email"] = user.email;
value["role"] = role_to_string(user.role);
value["createdAt"] = static_cast<Json::Int64>(timestamp_to_epoch_ms(user.created_at));
value["updatedAt"] = static_cast<Json::Int64>(timestamp_to_epoch_ms(user.updated_at));
return value;
}
Json::Value users_to_json(const std::vector<User>& users) {
Json::Value arr(Json::arrayValue);
for (const auto& user : users) {
arr.append(user_to_json(user));
}
return arr;
}
ListOptions list_options_from_json(const Json::Value& json) {
ListOptions options;
if (!json.isNull()) {
if (json.isMember("page") && json["page"].isInt()) {
options.page = json["page"].asInt();
}
if (json.isMember("limit") && json["limit"].isInt()) {
options.limit = json["limit"].asInt();
}
if (json.isMember("filter") && json["filter"].isObject()) {
for (const auto& key : json["filter"].getMemberNames()) {
options.filter[key] = json["filter"][key].asString();
}
}
if (json.isMember("sort") && json["sort"].isObject()) {
for (const auto& key : json["sort"].getMemberNames()) {
options.sort[key] = json["sort"][key].asString();
}
}
}
return options;
}
Json::Value list_response_value(const std::vector<User>& users, const ListOptions& options) {
Json::Value value(Json::objectValue);
value["data"] = users_to_json(users);
value["total"] = static_cast<Json::Int64>(users.size());
value["page"] = options.page;
value["limit"] = options.limit;
value["hasMore"] = Json::Value(false);
return value;
}
} // namespace daemon
} // namespace dbal

View File

@@ -11,9 +11,12 @@
box-sizing: border-box;
}
body {
margin: 0;
min-height: 100vh;
background-color: theme('colors.background');
color: theme('colors.foreground');
@layer base {
body {
margin: 0;
min-height: 100vh;
background-color: theme('colors.background');
color: theme('colors.foreground');
font-family: var(--font-body);
}
}

View File

@@ -1,4 +1,5 @@
import type { Metadata } from 'next'
import type { ReactNode } from 'react'
import { IBM_Plex_Sans, Space_Grotesk } from 'next/font/google'
import './globals.css'
@@ -20,7 +21,7 @@ export const metadata: Metadata = {
export default function RootLayout({
children,
}: {
children: React.ReactNode
children: ReactNode
}) {
return (
<html lang="en" className={`${ibmPlexSans.variable} ${spaceGrotesk.variable}`}>