Serenity Operating System
1/*
2 * Copyright (c) 2022, Tim Flynn <trflynn89@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#pragma once
8
9#include <AK/Error.h>
10#include <AK/Function.h>
11#include <AK/HashMap.h>
12#include <AK/NonnullRefPtr.h>
13#include <AK/Optional.h>
14#include <AK/RefCounted.h>
15#include <AK/StringView.h>
16#include <AK/Vector.h>
17#include <LibSQL/SQLClient.h>
18#include <LibSQL/Type.h>
19#include <LibSQL/Value.h>
20
21namespace Browser {
22
23class Database : public RefCounted<Database> {
24 using OnResult = Function<void(ReadonlySpan<SQL::Value>)>;
25 using OnComplete = Function<void()>;
26 using OnError = Function<void(StringView)>;
27
28public:
29 static ErrorOr<NonnullRefPtr<Database>> create();
30 static ErrorOr<NonnullRefPtr<Database>> create(NonnullRefPtr<SQL::SQLClient>);
31
32 ErrorOr<SQL::StatementID> prepare_statement(StringView statement);
33
34 template<typename... PlaceholderValues>
35 void execute_statement(SQL::StatementID statement_id, OnResult on_result, OnComplete on_complete, OnError on_error, PlaceholderValues&&... placeholder_values)
36 {
37 PendingExecution pending_execution {
38 .on_result = move(on_result),
39 .on_complete = move(on_complete),
40 .on_error = move(on_error),
41 };
42
43 Vector<SQL::Value> values { SQL::Value(forward<PlaceholderValues>(placeholder_values))... };
44 execute_statement(statement_id, move(values), move(pending_execution));
45 }
46
47private:
48 struct ExecutionKey {
49 constexpr bool operator==(ExecutionKey const&) const = default;
50
51 SQL::StatementID statement_id { 0 };
52 SQL::ExecutionID execution_id { 0 };
53 };
54
55 struct PendingExecution {
56 OnResult on_result { nullptr };
57 OnComplete on_complete { nullptr };
58 OnError on_error { nullptr };
59 };
60
61 struct ExecutionKeyTraits : public Traits<ExecutionKey> {
62 static constexpr unsigned hash(ExecutionKey const& key)
63 {
64 return pair_int_hash(u64_hash(key.statement_id), u64_hash(key.execution_id));
65 }
66 };
67
68 Database(NonnullRefPtr<SQL::SQLClient> sql_client, SQL::ConnectionID connection_id);
69 void execute_statement(SQL::StatementID statement_id, Vector<SQL::Value> placeholder_values, PendingExecution pending_execution);
70
71 template<typename ResultData>
72 auto find_pending_execution(ResultData const& result_data)
73 {
74 return m_pending_executions.find({ result_data.statement_id, result_data.execution_id });
75 }
76
77 NonnullRefPtr<SQL::SQLClient> m_sql_client;
78 SQL::ConnectionID m_connection_id { 0 };
79
80 HashMap<ExecutionKey, PendingExecution, ExecutionKeyTraits> m_pending_executions;
81};
82
83}