docudb  1.0
Loading...
Searching...
No Matches
docudb.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <string_view>
4#include <string>
5#include <vector>
6#include <stdexcept>
7#include <functional>
8
9#include <sqlite3.h>
10#include <cstdint>
11#include <cmath>
12#include <variant>
13#include <unordered_map>
14#include <memory>
15#include <format>
16
17// sqlite3 forward declarations
18struct sqlite3;
19struct sqlite3_stmt;
20
21namespace docudb
22{
23 /**
24 * \brief Types supported.
25 */
26 using db_value = std::variant<
27 std::float_t,
28 std::double_t,
29 std::int32_t,
30 std::int64_t,
31 std::nullptr_t,
32 std::string>;
33
34 /**
35 * \brief JSON types.
36 */
37 enum class json_type {
38 null,
39 integer,
40 real,
41 string,
42 object,
43 array,
47 };
48
49 /**
50 * \brief Specifies the database file open mode.
51 */
52 enum class open_mode {
53 /**
54 * \brief Open the database for read-only access. The database must already exist.
55 */
57 /**
58 * \brief Open the database for reading and writing. The database must already exist.
59 */
61 /**
62 * \brief Open the database for reading and writing, and create it if it does not exist.
63 */
65 };
66
67 /**
68 * \brief Specifies the threading mode for the database connection.
69 * \note The threading mode specified by these flags overrides the compile-time default.
70 * Refer to SQLite's documentation on sqlite3_open_v2 for details.
71 */
72 enum class threading_mode {
73 /**
74 * \brief Use the default threading mode. If you need single-thread mode, SQLite
75 * must be compiled accordingly. This option adds no specific threading flags.
76 */
78 /**
79 * \brief The new database connection will use the multi-thread threading mode.
80 */
82 /**
83 * \brief The new database connection will use the serialized threading mode.
84 */
86 };
87
88
89 namespace details::sqlite {
90
91 struct statement
92 {
93 statement(sqlite3 *db_handle, std::string_view query);
95 sqlite3_stmt *data() const noexcept;
96 statement &bind(int index, std::int16_t value);
97 statement &bind(int index, std::int32_t value);
98 statement &bind(int index, std::int64_t value);
99 statement &bind(int index, std::nullptr_t value);
100 statement &bind(int index, std::string_view value);
101 statement &bind(int index, std::double_t value);
102 statement &bind(int index, std::float_t value);
103 statement &step() noexcept;
104 template <typename T>
105 T get(int index) const
106 {
107 static_assert(std::false_type::value, "Unsupported type for get method");
108 }
109
110 json_type get_type(int index) const noexcept;
111
112 bool is_result_null(int index) const noexcept;
113
114 int result_code() const noexcept
115 {
116 return rc;
117 }
118
119 private:
120 sqlite3 *db_handle_;
121 sqlite3_stmt *stmt_;
122 int rc;
123 };
124
125 template <>
126 std::string statement::get(int index) const;
127 template <>
128 std::double_t statement::get(int index) const;
129 template <>
130 std::int64_t statement::get(int index) const;
131 template <>
132 std::int32_t statement::get(int index) const;
133 template <>
134 std::int16_t statement::get(int index) const;
135 template <>
136 std::uint64_t statement::get(int index) const;
137 template <>
138 std::uint32_t statement::get(int index) const;
139 template <>
140 std::uint16_t statement::get(int index) const;
141 }
142
143 namespace query
144 {
145 /**
146 * \brief Represents a binder for query parameters.
147 */
148 struct binder
149 {
150 const std::unordered_map<int, db_value> &get_parameters() const
151 {
152 return bind_map;
153 }
154
155 void merge(binder &b)
156 {
157 bind_map.merge(b.bind_map);
158 }
159
160 void add(int index, db_value &&v)
161 {
162 bind_map.emplace(index, std::move(v));
163 }
164
165 private:
166 std::unordered_map<int, db_value> bind_map;
167 };
168
169 /**
170 * \brief Represents a queryable object.
171 */
172 template <typename T>
173 concept Queryable = requires(T x) {
174 { x.to_query_string() } -> std::same_as<std::string>;
175 { x.get_binder() } -> std::same_as<binder &>;
176 };
177
178 /**
179 * \brief Represents a logic gate for combining two queryable objects.
180 */
181 template <Queryable A, Queryable B>
183 {
184
185 explicit logic_gate(A &&a, B &&b, std::string const &gate) : a_(std::move(a)), b_(std::move(b)), gate_(gate)
186 {
187 binder_.merge(a_.get_binder());
188 binder_.merge(b_.get_binder());
189 }
190
191 std::string to_query_string() const
192 {
193 return std::format("{} {} {}", a_.to_query_string(), gate_, b_.to_query_string());
194 }
195
196 binder const &get_binder() const
197 {
198 return binder_;
199 }
200
202 {
203 return binder_;
204 }
205
206 private:
207 A a_;
208 B b_;
209 std::string gate_;
210 binder binder_;
211 };
212
213 /**
214 * \brief Represents a LOGIC AND gate.
215 */
216 template <Queryable A, Queryable B>
217 struct logic_and : logic_gate<A, B>
218 {
219
220 explicit logic_and(A &&a, B &&b) : logic_gate<A, B>(std::move(a), std::move(b), "AND")
221 {
222 }
223 };
224
225 /**
226 * \brief Represents a LOGIC OR gate.
227 */
228 template <Queryable A, Queryable B>
229 struct logic_or : logic_gate<A, B>
230 {
231
232 explicit logic_or(A &&a, B &&b) : logic_gate<A, B>(std::move(a), std::move(b), "OR")
233 {
234 }
235 };
236
237 extern thread_local int bind_counter;
238 const int MAX_VAR_NUM = 250000;
239
240 /**
241 * \brief Represents a binary operation for querying.
242 */
244 {
245 explicit binary_op(
246 std::string const &json_query,
247 std::string const &op,
248 db_value &&value) : var_(json_query), op_(op), index_(1 + (++bind_counter % MAX_VAR_NUM))
249 {
250 binder_.add(index_, std::move(value));
251 }
252
253 explicit binary_op(
254 std::string const &json_query,
255 std::string const &op,
256 nullptr_t) : var_(json_query), op_(op), index_(-1)
257 {
258
259 }
260
261 std::string to_query_string() const
262 {
263 auto json_query = var_.size() > 0 && var_[0] == '$';
264 auto is_value_null = index_ == -1;
265
266 // special case for null value
267 if (is_value_null) {
268 if (json_query)
269 return std::format("json_type(body, '{0}') IS NOT NULL AND json_extract(body, '{0}') {1} NULL", var_, op_);
270 else
271 return std::format("[{}] {} NULL", var_, op_);
272 }
273
274 if (json_query)
275 return std::format("(json_extract(body, '{}') {} ?{})", var_, op_, index_);
276 else
277 return std::format("([{}] {} ?{})", var_, op_, index_);
278 }
279
280 binder const &get_binder() const
281 {
282 return binder_;
283 }
284
286 {
287 return binder_;
288 }
289
290 private:
291 std::string var_;
292 std::string op_;
293 binder binder_;
294 int index_;
295 };
296
297 /**
298 * \brief Represents a LIKE operation for querying.
299 */
301 {
302 explicit like(
303 std::string const &name,
304 std::string const &val) : binary_op(name, "LIKE", val) {}
305 };
306
307 /**
308 * \brief Represents a REGEXP operation for querying.
309 */
311 {
312 explicit regexp(
313 std::string const &name,
314 std::string const &val) : binary_op(name, "REGEXP", val) {}
315 };
316
317 /**
318 * \brief Represents an EQUAL operation for querying.
319 */
320 struct eq : binary_op
321 {
322 explicit eq(
323 std::string const &name,
324 db_value &&val) : binary_op(name, "=", std::move(val)) {}
325
326 explicit eq(
327 std::string const &name,
328 nullptr_t) : binary_op(name, "IS", nullptr) {}
329 };
330
331 /**
332 * \brief Represents a NOT EQUAL operation for querying.
333 */
334 struct neq : binary_op
335 {
336 explicit neq(
337 std::string const &name,
338 db_value &&val) : binary_op(name, "!=", std::move(val)) {}
339
340 explicit neq(
341 std::string const &name,
342 nullptr_t) : binary_op(name, "IS NOT", nullptr) {}
343 };
344
345 /**
346 * \brief Represents a GREATER THAN operation for querying.
347 */
348 struct gt : binary_op
349 {
350 explicit gt(
351 std::string const &name,
352 db_value &&val) : binary_op(name, ">", std::move(val)) {}
353 };
354
355 /**
356 * \brief Represents a LESSER THAN operation for querying.
357 */
358 struct lt : binary_op
359 {
360 explicit lt(
361 std::string const &name,
362 db_value &&val) : binary_op(name, "<", std::move(val)) {}
363 };
364
365 /**
366 * \brief Represents a GREATER OR EQUAL THAN operation for querying.
367 */
368 struct gte : binary_op
369 {
370 explicit gte(
371 std::string const &name,
372 db_value &&val) : binary_op(name, ">=", std::move(val)) {}
373 };
374
375 /**
376 * \brief Represents a LESSER OR EQUAL THAN operation for querying.
377 */
378 struct lte : binary_op
379 {
380 explicit lte(
381 std::string const &name,
382 db_value &&val) : binary_op(name, "<=", std::move(val)) {}
383 };
384
385 template <Queryable A, Queryable B>
387 {
388 return logic_and<A, B>{std::forward<A>(a), std::forward<B>(b)};
389 }
390
391 template <Queryable A, Queryable B>
393 {
394 return logic_or<A, B>{std::forward<A>(a), std::forward<B>(b)};
395 }
396
397 /**
398 * \brief Abstract base class for Queryable objects.
399 */
401 {
402 virtual ~queryable_base() = default;
403
404 // Pure virtual methods
405 virtual std::string to_query_string() const = 0;
406 virtual binder get_binder() const = 0;
407 };
408
409 /**
410 * \brief Concrete wrapper for erasing the type of a Queryable object.
411 */
412 template <Queryable T>
414 {
415 explicit queryable_wrapper(T &&obj) : obj_(std::forward<T>(obj)) {}
416
417 std::string to_query_string() const override
418 {
419 return obj_.to_query_string();
420 }
421
422 binder get_binder() const override
423 {
424 return obj_.get_binder();
425 }
426
427 private:
428 T obj_;
429 };
430
431 /**
432 * \brief Type-erased Queryable object.
433 */
435 {
436 template <Queryable T>
438 : ptr_(std::make_unique<queryable_wrapper<T>>(std::forward<T>(obj))) {}
439
440 std::string to_query_string() const
441 {
442 return ptr_->to_query_string();
443 }
444
446 {
447 return ptr_->get_binder();
448 }
449
450 private:
451 std::unique_ptr<queryable_base> ptr_;
452 };
453
454 struct order_by
455 {
456 explicit order_by(std::string const &field, bool ascending = true)
457 : field_(field), ascending_(ascending) {}
458
459 std::string const& field() const { return field_; }
460 std::string_view direction() const { return ascending_ ? "ASC" : "DESC"; }
461
462 private:
463 std::string field_;
464 bool ascending_;
465 };
466 }
467
468 /**
469 * \brief Gets the version of the library.
470 *
471 * \returns std::string The version string.
472 */
473 std::string get_version() noexcept;
474
475 /**
476 * \brief Gets the build timestamp.
477 *
478 * \returns std::string The timestamp string.
479 */
480 std::string get_build_timestamp() noexcept;
481
482 /**
483 * \brief Exception class for database errors.
484 */
485 struct db_exception : std::runtime_error
486 {
487 /**
488 * \brief Constructs a new db_exception object.
489 *
490 * \param db_handle The SQLite database handle.
491 * \param msg The error message.
492 */
493 db_exception(sqlite3 *db_handle, std::string_view msg);
494 };
495
496 /**
497 * \brief Exception class for database errors.
498 */
500 {
501 /**
502 * \brief Constructs a new db_exception object.
503 *
504 * \param db_handle The SQLite database handle.
505 * \param msg The failing statement.
506 */
507 stmt_exception(sqlite3 *db_handle, std::string_view sql);
508 };
509
510 struct db_document;
511
512 /**
513 * \brief Reference to a database document.
514 */
516 {
517 /**
518 * \brief Constructs a new db_document_ref object from a db_document object.
519 *
520 * \param doc The document object.
521 */
523
524 /**
525 * \brief Constructs a new db_document_ref object.
526 *
527 * \param table_name The name of the table.
528 * \param doc_id The document ID.
529 * \param db_handle The SQLite database handle.
530 */
531 db_document_ref(std::string_view table_name, std::string_view doc_id, sqlite3 *db_handle);
532
533 /**
534 * \brief Gets the document ID.
535 *
536 * \returns std::string The document ID.
537 */
538 std::string id() const;
539
540 /**
541 * \brief Gets the full document object.
542 *
543 * \returns db_document The document object.
544 */
546
547 /**
548 * \brief Removes the document from the collection.
549 * \returns void
550 */
551 void erase();
552
553 private:
554 sqlite3 *db_handle;
555 std::string table_name;
556 std::string doc_id;
557 };
558
559 /**
560 * \brief Represents a database document.
561 */
563 {
564 /**
565 * \brief Gets the document ID.
566 *
567 * \returns std::string The document ID.
568 */
569 std::string id() const;
570
571 /**
572 * \brief Gets the full body of the document.
573 *
574 * \returns std::string The document body.
575 */
576 std::string body() const;
577
578 /**
579 * \brief Sets the full body of the document.
580 *
581 * \param body The new body content.
582 * \returns db_document& Reference to the document.
583 */
584 db_document &body(std::string_view body);
585
586 /**
587 * \brief Replace a value in the json body
588 *
589 * \param query The query that points to the value to replace.
590 * \param value The new value
591 * \returns db_document& Reference to the document.
592 */
593 db_document &replace(std::string_view query, std::float_t value);
594
595 /**
596 * \brief Replace a value in the json body
597 *
598 * \param query The query that points to the value to replace.
599 * \param value The new value
600 * \returns db_document& Reference to the document.
601 */
602 db_document &replace(std::string_view query, std::double_t value);
603
604 /**
605 * \brief Replace a value in the json body
606 *
607 * \param query The query that points to the value to replace.
608 * \param value The new value
609 * \returns db_document& Reference to the document.
610 */
611 db_document &replace(std::string_view query, std::int32_t value);
612
613 /**
614 * \brief Replace a value in the json body
615 *
616 * \param query The query that points to the value to replace.
617 * \param value The new value
618 * \returns db_document& Reference to the document.
619 */
620 db_document &replace(std::string_view query, std::int64_t value);
621
622 /**
623 * \brief Replace a value in the json body
624 *
625 * \param query The query that points to the value to replace.
626 * \param value The new value
627 * \returns db_document& Reference to the document.
628 */
629 db_document &replace(std::string_view query, std::nullptr_t value);
630
631 /**
632 * \brief Replace a value in the json body
633 *
634 * \param query The query that points to the value to replace.
635 * \param value The new value
636 * \returns db_document& Reference to the document.
637 */
638 db_document &replace(std::string_view query, std::string const &value);
639
640 /**
641 * \brief Replace a value in the json body
642 *
643 * \param query The query that points to the value to replace.
644 * \param value The new value
645 * \returns db_document& Reference to the document.
646 */
647 db_document &replace(std::string_view query, std::string_view value);
648
649 // set value in json body
650 db_document &set(std::string_view query, std::float_t value);
651 db_document &set(std::string_view query, std::double_t value);
652 db_document &set(std::string_view query, std::int32_t value);
653 db_document &set(std::string_view query, std::int64_t value);
654 db_document &set(std::string_view query, std::nullptr_t value);
655 db_document &set(std::string_view query, std::string const &value);
656 db_document &set(std::string_view query, std::string_view value);
657
658 // insert value in json body
659 db_document &insert(std::string_view query, std::float_t value);
660 db_document &insert(std::string_view query, std::double_t value);
661 db_document &insert(std::string_view query, std::int32_t value);
662 db_document &insert(std::string_view query, std::int64_t value);
663 db_document &insert(std::string_view query, std::nullptr_t value);
664 db_document &insert(std::string_view query, std::string const &value);
665 db_document &insert(std::string_view query, std::string_view value);
666
667 /**
668 * \brief Patches the JSON body of the document.
669 *
670 * \param json The JSON patch.
671 * \returns db_document& Reference to the document.
672 */
673 db_document &patch(std::string_view json);
674
675 // get string
676 std::string get_string(std::string_view query) const;
677
678 // get number
679 std::int64_t get_number(std::string_view query) const;
680
681 // get real
682 std::double_t get_real(std::string_view query) const;
683
684 // get json type
685 json_type get_type(std::string_view query) const;
686
687 // get array length
688 std::size_t get_array_length(std::string_view query) const;
689
690 // get object keys
691 std::vector<std::string> get_object_keys(std::string_view query) const;
692
693 // get values
694 template <typename... Types>
695 std::tuple<Types...> get(const std::vector<std::string>& fields) const {
696 if (fields.size() != sizeof...(Types)) {
697 throw std::invalid_argument("Number of fields does not match the number of types.");
698 }
699
700 auto stmt = get_value_stmt_impl(fields);
701 auto ret = get_values_impl<Types...>(stmt, std::index_sequence_for<Types...>{});
702
703 return ret;
704 }
705
706 /**
707 * \brief Removes the document from the collection.
708 * \returns void
709 */
710 void erase();
711 private:
712 template <typename... Types, std::size_t... Indices>
713 std::tuple<Types...> get_values_impl(details::sqlite::statement const &stmt, std::index_sequence<Indices...>) const
714 {
715 return std::make_tuple(stmt.get<Types>(Indices)...);
716 }
717
718 details::sqlite::statement get_value_stmt_impl(const std::vector<std::string>& fields) const;
719
720 private:
721 std::string doc_id;
722 std::string table_name;
723 mutable std::string body_data;
724 bool invalid_body;
725 sqlite3 *db_handle;
726 friend struct db_collection;
727 friend struct db_document_ref;
728
729 /**
730 * \brief Constructs a new db_document object.
731 *
732 * \param table_name The name of the table.
733 * \param doc_id The document ID.
734 * \param body The document body.
735 * \param db_handle The SQLite database handle.
736 */
737 db_document(std::string_view table_name, std::string_view doc_id, std::string_view body, sqlite3 *db_handle);
738 db_document(std::string_view table, std::string_view doc_id, sqlite3 *db_handle);
739 };
740
741 /**
742 * \brief Represents a collection of documents in the database.
743 */
745 {
746 /**
747 * \brief Constructs an empty db_collection object.
748 *
749 */
750 db_collection() = default;
751 db_collection(db_collection const &) = delete;
755
756 /**
757 * \brief Constructs a new db_collection object.
758 *
759 * \param name The name of the collection.
760 * \param db_handle The SQLite database handle.
761 */
762 db_collection(std::string_view name, sqlite3 *db_handle);
763
764 /**
765 * \brief Gets the collection name
766 *
767 * \returns std::string The collection name.
768 */
769 std::string name() const noexcept;
770
771 /**
772 * \brief Gets a document by ID.
773 *
774 * \param doc_id The document ID.
775 * \returns db_document The document object.
776 */
777 db_document doc(std::string_view doc_id) const;
778
779 /**
780 * \brief Creates a new document with a generated UUID.
781 *
782 * \returns db_document The new document object.
783 */
785
786 /**
787 * \brief Creates a new document with the given ID.
788 *
789 * \returns db_document The new document object.
790 */
791 db_document create(std::string_view doc_id);
792
793 /**
794 * \brief Gets the number of documents in the collection.
795 *
796 * \returns std::size_t The number of documents in the collection.
797 */
798 std::size_t count() const;
799
800 /**
801 * \brief Gets the number of documents that matches the given query.
802 *
803 * \param q The query object.
804 * \returns std::size_t The number of matching documents.
805 */
806 std::size_t count(query::queryable_type_eraser q) const;
807
808 /**
809 * \brief Gets all documents in the collection.
810 *
811 * \returns std::vector<db_document_ref> The list of document references.
812 */
813 std::vector<db_document_ref> docs() const;
814
815 /**
816 * \brief Removes a document by ID.
817 *
818 * \param doc_id The document ID.
819 */
820 void remove(std::string_view doc_id);
821
822 /**
823 * \brief Searches documents by query.
824 *
825 * \param q The query object.
826 * \param order_by The order by object (optional)
827 * \param limit The maximum number of documents to return (optional).
828 * \returns std::vector<db_document_ref> The list of document references.
829 */
830 std::vector<db_document_ref> find(query::queryable_type_eraser q, std::optional<query::order_by> order_by = std::nullopt, std::optional<int> limit = std::nullopt) const;
831
832 /**
833 * \brief Indexes the document based on the specified column and query.
834 *
835 * This function creates a new virtual column representing the given json query
836 * and add an index to that column.
837 *
838 * \param column_name The name of the column to be created.
839 * \param query The json query string in SQLite format representing the field to be indexed
840 * \param unique The index should be unique
841 * \return A reference to the document.
842 */
843 db_collection& index(std::string_view column_name, std::string_view query, bool unique = false);
844
845 /**
846 * \brief Indexes the document based on the specified columns and query.
847 *
848 * This function creates a new virtual column representing the given json query
849 * and add an index to that column.
850 * \param name The index name
851 * \param columns A vector of pairs [column_name, query]
852 * \param unique The index should be unique
853 * \return A reference to the document.
854 */
856 std::string name,
857 std::vector<std::pair<std::string, std::string>> const &columns,
858 bool unique);
859 private:
860 sqlite3 *db_handle;
861 std::string table_name;
862 };
863
864 /**
865 * \brief Represents the database.
866 */
867 struct database
868 {
869 /**
870 * \brief Constructs an empty database object.
871 *
872 */
873 database() = default;
874 database(database const &) = delete;
875 database &operator=(database const &) = delete;
876
879
880 /**
881 * \brief Constructs a new database object.
882 *
883 * \param connection_string A valid connection string to the database (e.g. the database file path or :memory:).
884 */
885 explicit database(std::string_view connection_string);
886
887 /**
888 * \brief Constructs a new database object.
889 *
890 * \param connection_string A valid connection string to the database (e.g. the database file path or :memory:).
891 * \param mode The mode for opening the database file.
892 * \param thread_mode The threading model for the connection.
893 */
894 explicit database(
895 std::string_view connection_string,
896 open_mode mode,
897 threading_mode thread_mode);
898
899 /**
900 * \brief Destroys the database object.
901 */
903
904 /**
905 * \brief Gets a collection by name.
906 *
907 * \param name The name of the collection.
908 * \returns db_collection The collection object.
909 */
910 db_collection collection(std::string_view name) const;
911
912 /**
913 * \brief Gets all collections
914 *
915 * \returns std::vector<db_collection> The collection list.
916 */
917 std::vector<db_collection> collections() const;
918
919 /**
920 * \brief Load docudb's sqlite3 extensions (e.g. regexp)
921 *
922 */
923 void load_extensions() const;
924
925 /**
926 * \brief Backup the current database into the destination database
927 *
928 * \param name The destination database.
929 * \param progress Progress callback void progress(int remaining, int total) { ... }
930 */
931 void backup_to(database& dest, std::function<void(int, int)> progress = [](int, int){}) const;
932
933 /**
934 * \brief Returns the database file name
935 *
936 */
937 std::string filename_database() const noexcept;
938
939 /**
940 * \brief Returns the database journal file name
941 *
942 */
943 std::string filename_journal() const noexcept;
944
945 /**
946 * \brief Returns the database write-ahead log file name
947 *
948 */
949 std::string filename_wal() const noexcept;
950
951 private:
952 sqlite3 *db_handle;
953 };
954}
Represents a queryable object.
Definition docudb.hpp:173
logic_or< A, B > operator||(A &&a, B &&b)
Definition docudb.hpp:392
const int MAX_VAR_NUM
Definition docudb.hpp:238
logic_and< A, B > operator&&(A &&a, B &&b)
Definition docudb.hpp:386
thread_local int bind_counter
std::string get_version() noexcept
Gets the version of the library.
open_mode
Specifies the database file open mode.
Definition docudb.hpp:52
@ read_write
Open the database for reading and writing. The database must already exist.
@ read_write_create
Open the database for reading and writing, and create it if it does not exist.
@ read_only
Open the database for read-only access. The database must already exist.
json_type
JSON types.
Definition docudb.hpp:37
threading_mode
Specifies the threading mode for the database connection.
Definition docudb.hpp:72
@ multi_thread
The new database connection will use the multi-thread threading mode.
@ default_mode
Use the default threading mode. If you need single-thread mode, SQLite must be compiled accordingly....
@ serialized
The new database connection will use the serialized threading mode.
std::string get_build_timestamp() noexcept
Gets the build timestamp.
std::variant< std::float_t, std::double_t, std::int32_t, std::int64_t, std::nullptr_t, std::string > db_value
Types supported.
Definition docudb.hpp:26
Represents the database.
Definition docudb.hpp:868
void backup_to(database &dest, std::function< void(int, int)> progress=[](int, int){}) const
Backup the current database into the destination database.
void load_extensions() const
Load docudb's sqlite3 extensions (e.g. regexp)
std::string filename_database() const noexcept
Returns the database file name.
database()=default
Constructs an empty database object.
std::vector< db_collection > collections() const
Gets all collections.
db_collection collection(std::string_view name) const
Gets a collection by name.
database(std::string_view connection_string)
Constructs a new database object.
database(database &&)
database & operator=(database &&)
database(std::string_view connection_string, open_mode mode, threading_mode thread_mode)
Constructs a new database object.
database(database const &)=delete
database & operator=(database const &)=delete
~database()
Destroys the database object.
Represents a collection of documents in the database.
Definition docudb.hpp:745
db_collection & operator=(db_collection const &)=delete
db_document create(std::string_view doc_id)
Creates a new document with the given ID.
db_collection()=default
Constructs an empty db_collection object.
std::string name() const noexcept
Gets the collection name.
db_collection(db_collection const &)=delete
db_collection & index(std::string_view column_name, std::string_view query, bool unique=false)
Indexes the document based on the specified column and query.
void remove(std::string_view doc_id)
Removes a document by ID.
db_document doc()
Creates a new document with a generated UUID.
db_collection(std::string_view name, sqlite3 *db_handle)
Constructs a new db_collection object.
std::size_t count() const
Gets the number of documents in the collection.
db_collection & operator=(db_collection &&)=default
std::vector< db_document_ref > find(query::queryable_type_eraser q, std::optional< query::order_by > order_by=std::nullopt, std::optional< int > limit=std::nullopt) const
Searches documents by query.
db_collection(db_collection &&)=default
std::vector< db_document_ref > docs() const
Gets all documents in the collection.
Reference to a database document.
Definition docudb.hpp:516
db_document_ref(db_document const &doc)
Constructs a new db_document_ref object from a db_document object.
db_document_ref(std::string_view table_name, std::string_view doc_id, sqlite3 *db_handle)
Constructs a new db_document_ref object.
std::string id() const
Gets the document ID.
db_document doc() const
Gets the full document object.
void erase()
Removes the document from the collection.
Represents a database document.
Definition docudb.hpp:563
std::double_t get_real(std::string_view query) const
std::string get_string(std::string_view query) const
db_document & set(std::string_view query, std::float_t value)
db_document & insert(std::string_view query, std::nullptr_t value)
db_document & patch(std::string_view json)
Patches the JSON body of the document.
db_document & insert(std::string_view query, std::int32_t value)
db_document & insert(std::string_view query, std::float_t value)
db_document & insert(std::string_view query, std::int64_t value)
db_document & body(std::string_view body)
Sets the full body of the document.
db_document & set(std::string_view query, std::string const &value)
db_document & set(std::string_view query, std::string_view value)
std::string id() const
Gets the document ID.
db_document & replace(std::string_view query, std::string const &value)
Replace a value in the json body.
db_document & replace(std::string_view query, std::double_t value)
Replace a value in the json body.
std::int64_t get_number(std::string_view query) const
db_document & replace(std::string_view query, std::float_t value)
Replace a value in the json body.
db_document & replace(std::string_view query, std::int64_t value)
Replace a value in the json body.
std::vector< std::string > get_object_keys(std::string_view query) const
db_document & set(std::string_view query, std::int32_t value)
db_document & insert(std::string_view query, std::string_view value)
db_document & insert(std::string_view query, std::string const &value)
void erase()
Removes the document from the collection.
std::tuple< Types... > get(const std::vector< std::string > &fields) const
Definition docudb.hpp:695
std::size_t get_array_length(std::string_view query) const
std::string body() const
Gets the full body of the document.
db_document & insert(std::string_view query, std::double_t value)
db_document & set(std::string_view query, std::nullptr_t value)
json_type get_type(std::string_view query) const
db_document & set(std::string_view query, std::int64_t value)
db_document & replace(std::string_view query, std::string_view value)
Replace a value in the json body.
db_document & set(std::string_view query, std::double_t value)
db_document & replace(std::string_view query, std::int32_t value)
Replace a value in the json body.
db_document & replace(std::string_view query, std::nullptr_t value)
Replace a value in the json body.
Exception class for database errors.
Definition docudb.hpp:486
db_exception(sqlite3 *db_handle, std::string_view msg)
Constructs a new db_exception object.
json_type get_type(int index) const noexcept
bool is_result_null(int index) const noexcept
int result_code() const noexcept
Definition docudb.hpp:114
statement & bind(int index, std::int16_t value)
statement(sqlite3 *db_handle, std::string_view query)
sqlite3_stmt * data() const noexcept
statement & step() noexcept
Represents a binary operation for querying.
Definition docudb.hpp:244
binary_op(std::string const &json_query, std::string const &op, db_value &&value)
Definition docudb.hpp:245
binder const & get_binder() const
Definition docudb.hpp:280
binary_op(std::string const &json_query, std::string const &op, nullptr_t)
Definition docudb.hpp:253
std::string to_query_string() const
Definition docudb.hpp:261
Represents a binder for query parameters.
Definition docudb.hpp:149
const std::unordered_map< int, db_value > & get_parameters() const
Definition docudb.hpp:150
void merge(binder &b)
Definition docudb.hpp:155
void add(int index, db_value &&v)
Definition docudb.hpp:160
Represents an EQUAL operation for querying.
Definition docudb.hpp:321
eq(std::string const &name, db_value &&val)
Definition docudb.hpp:322
eq(std::string const &name, nullptr_t)
Definition docudb.hpp:326
Represents a GREATER THAN operation for querying.
Definition docudb.hpp:349
gt(std::string const &name, db_value &&val)
Definition docudb.hpp:350
Represents a GREATER OR EQUAL THAN operation for querying.
Definition docudb.hpp:369
gte(std::string const &name, db_value &&val)
Definition docudb.hpp:370
Represents a LIKE operation for querying.
Definition docudb.hpp:301
like(std::string const &name, std::string const &val)
Definition docudb.hpp:302
Represents a LOGIC AND gate.
Definition docudb.hpp:218
logic_and(A &&a, B &&b)
Definition docudb.hpp:220
Represents a logic gate for combining two queryable objects.
Definition docudb.hpp:183
logic_gate(A &&a, B &&b, std::string const &gate)
Definition docudb.hpp:185
binder const & get_binder() const
Definition docudb.hpp:196
std::string to_query_string() const
Definition docudb.hpp:191
Represents a LOGIC OR gate.
Definition docudb.hpp:230
logic_or(A &&a, B &&b)
Definition docudb.hpp:232
Represents a LESSER THAN operation for querying.
Definition docudb.hpp:359
lt(std::string const &name, db_value &&val)
Definition docudb.hpp:360
Represents a LESSER OR EQUAL THAN operation for querying.
Definition docudb.hpp:379
lte(std::string const &name, db_value &&val)
Definition docudb.hpp:380
Represents a NOT EQUAL operation for querying.
Definition docudb.hpp:335
neq(std::string const &name, db_value &&val)
Definition docudb.hpp:336
neq(std::string const &name, nullptr_t)
Definition docudb.hpp:340
std::string_view direction() const
Definition docudb.hpp:460
order_by(std::string const &field, bool ascending=true)
Definition docudb.hpp:456
std::string const & field() const
Definition docudb.hpp:459
Abstract base class for Queryable objects.
Definition docudb.hpp:401
virtual ~queryable_base()=default
virtual std::string to_query_string() const =0
virtual binder get_binder() const =0
Type-erased Queryable object.
Definition docudb.hpp:435
std::string to_query_string() const
Definition docudb.hpp:440
Concrete wrapper for erasing the type of a Queryable object.
Definition docudb.hpp:414
std::string to_query_string() const override
Definition docudb.hpp:417
binder get_binder() const override
Definition docudb.hpp:422
Represents a REGEXP operation for querying.
Definition docudb.hpp:311
regexp(std::string const &name, std::string const &val)
Definition docudb.hpp:312
Exception class for database errors.
Definition docudb.hpp:500
stmt_exception(sqlite3 *db_handle, std::string_view sql)
Constructs a new db_exception object.