Clio develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
Schema.hpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of clio: https://github.com/XRPLF/clio
4 Copyright (c) 2023, the clio developers.
5
6 Permission to use, copy, modify, and distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#pragma once
21
22#include "data/cassandra/Concepts.hpp"
23#include "data/cassandra/Handle.hpp"
24#include "data/cassandra/Types.hpp"
25#include "util/log/Logger.hpp"
26
27#include <fmt/compile.h>
28
29#include <functional>
30#include <memory>
31#include <string>
32#include <string_view>
33#include <vector>
34
35namespace data::cassandra {
36
45template <SomeSettingsProvider SettingsProviderType>
46[[nodiscard]] std::string inline qualifiedTableName(SettingsProviderType const& provider, std::string_view name)
47{
48 return fmt::format("{}.{}{}", provider.getKeyspace(), provider.getTablePrefix().value_or(""), name);
49}
50
54template <SomeSettingsProvider SettingsProviderType>
55class Schema {
56 util::Logger log_{"Backend"};
57 std::reference_wrapper<SettingsProviderType const> settingsProvider_;
58
59public:
65 explicit Schema(SettingsProviderType const& settingsProvider) : settingsProvider_{std::cref(settingsProvider)}
66 {
67 }
68
69 std::string createKeyspace = [this]() {
70 return fmt::format(
71 R"(
72 CREATE KEYSPACE IF NOT EXISTS {}
73 WITH replication = {{
74 'class': 'SimpleStrategy',
75 'replication_factor': '{}'
76 }}
77 AND durable_writes = True
78 )",
79 settingsProvider_.get().getKeyspace(),
80 settingsProvider_.get().getReplicationFactor()
81 );
82 }();
83
84 // =======================
85 // Schema creation queries
86 // =======================
87
88 std::vector<Statement> createSchema = [this]() {
89 std::vector<Statement> statements;
90
91 statements.emplace_back(fmt::format(
92 R"(
93 CREATE TABLE IF NOT EXISTS {}
94 (
95 key blob,
96 sequence bigint,
97 object blob,
98 PRIMARY KEY (key, sequence)
99 )
100 WITH CLUSTERING ORDER BY (sequence DESC)
101 )",
102 qualifiedTableName(settingsProvider_.get(), "objects")
103 ));
104
105 statements.emplace_back(fmt::format(
106 R"(
107 CREATE TABLE IF NOT EXISTS {}
108 (
109 hash blob PRIMARY KEY,
110 ledger_sequence bigint,
111 date bigint,
112 transaction blob,
113 metadata blob
114 )
115 )",
116 qualifiedTableName(settingsProvider_.get(), "transactions")
117 ));
118
119 statements.emplace_back(fmt::format(
120 R"(
121 CREATE TABLE IF NOT EXISTS {}
122 (
123 ledger_sequence bigint,
124 hash blob,
125 PRIMARY KEY (ledger_sequence, hash)
126 )
127 )",
128 qualifiedTableName(settingsProvider_.get(), "ledger_transactions")
129 ));
130
131 statements.emplace_back(fmt::format(
132 R"(
133 CREATE TABLE IF NOT EXISTS {}
134 (
135 key blob,
136 seq bigint,
137 next blob,
138 PRIMARY KEY (key, seq)
139 )
140 )",
141 qualifiedTableName(settingsProvider_.get(), "successor")
142 ));
143
144 statements.emplace_back(fmt::format(
145 R"(
146 CREATE TABLE IF NOT EXISTS {}
147 (
148 seq bigint,
149 key blob,
150 PRIMARY KEY (seq, key)
151 )
152 )",
153 qualifiedTableName(settingsProvider_.get(), "diff")
154 ));
155
156 statements.emplace_back(fmt::format(
157 R"(
158 CREATE TABLE IF NOT EXISTS {}
159 (
160 account blob,
161 seq_idx tuple<bigint, bigint>,
162 hash blob,
163 PRIMARY KEY (account, seq_idx)
164 )
165 WITH CLUSTERING ORDER BY (seq_idx DESC)
166 )",
167 qualifiedTableName(settingsProvider_.get(), "account_tx")
168 ));
169
170 statements.emplace_back(fmt::format(
171 R"(
172 CREATE TABLE IF NOT EXISTS {}
173 (
174 sequence bigint PRIMARY KEY,
175 header blob
176 )
177 )",
178 qualifiedTableName(settingsProvider_.get(), "ledgers")
179 ));
180
181 statements.emplace_back(fmt::format(
182 R"(
183 CREATE TABLE IF NOT EXISTS {}
184 (
185 hash blob PRIMARY KEY,
186 sequence bigint
187 )
188 )",
189 qualifiedTableName(settingsProvider_.get(), "ledger_hashes")
190 ));
191
192 statements.emplace_back(fmt::format(
193 R"(
194 CREATE TABLE IF NOT EXISTS {}
195 (
196 is_latest boolean PRIMARY KEY,
197 sequence bigint
198 )
199 )",
200 qualifiedTableName(settingsProvider_.get(), "ledger_range")
201 ));
202
203 statements.emplace_back(fmt::format(
204 R"(
205 CREATE TABLE IF NOT EXISTS {}
206 (
207 token_id blob,
208 sequence bigint,
209 owner blob,
210 is_burned boolean,
211 PRIMARY KEY (token_id, sequence)
212 )
213 WITH CLUSTERING ORDER BY (sequence DESC)
214 )",
215 qualifiedTableName(settingsProvider_.get(), "nf_tokens")
216 ));
217
218 statements.emplace_back(fmt::format(
219 R"(
220 CREATE TABLE IF NOT EXISTS {}
221 (
222 issuer blob,
223 taxon bigint,
224 token_id blob,
225 PRIMARY KEY (issuer, taxon, token_id)
226 )
227 WITH CLUSTERING ORDER BY (taxon ASC, token_id ASC)
228 )",
229 qualifiedTableName(settingsProvider_.get(), "issuer_nf_tokens_v2")
230 ));
231
232 statements.emplace_back(fmt::format(
233 R"(
234 CREATE TABLE IF NOT EXISTS {}
235 (
236 token_id blob,
237 sequence bigint,
238 uri blob,
239 PRIMARY KEY (token_id, sequence)
240 )
241 WITH CLUSTERING ORDER BY (sequence DESC)
242 )",
243 qualifiedTableName(settingsProvider_.get(), "nf_token_uris")
244 ));
245
246 statements.emplace_back(fmt::format(
247 R"(
248 CREATE TABLE IF NOT EXISTS {}
249 (
250 token_id blob,
251 seq_idx tuple<bigint, bigint>,
252 hash blob,
253 PRIMARY KEY (token_id, seq_idx)
254 )
255 WITH CLUSTERING ORDER BY (seq_idx DESC)
256 )",
257 qualifiedTableName(settingsProvider_.get(), "nf_token_transactions")
258 ));
259
260 statements.emplace_back(fmt::format(
261 R"(
262 CREATE TABLE IF NOT EXISTS {}
263 (
264 mpt_id blob,
265 holder blob,
266 PRIMARY KEY (mpt_id, holder)
267 )
268 WITH CLUSTERING ORDER BY (holder ASC)
269 )",
270 qualifiedTableName(settingsProvider_.get(), "mp_token_holders")
271 ));
272
273 statements.emplace_back(fmt::format(
274 R"(
275 CREATE TABLE IF NOT EXISTS {}
276 (
277 migrator_name TEXT,
278 status TEXT,
279 PRIMARY KEY (migrator_name)
280 )
281 )",
282 qualifiedTableName(settingsProvider_.get(), "migrator_status")
283 ));
284
285 return statements;
286 }();
287
292 std::reference_wrapper<SettingsProviderType const> settingsProvider_;
293 std::reference_wrapper<Handle const> handle_;
294
295 public:
302 Statements(SettingsProviderType const& settingsProvider, Handle const& handle)
303 : settingsProvider_{settingsProvider}, handle_{std::cref(handle)}
304 {
305 }
306
307 //
308 // Insert queries
309 //
310
311 PreparedStatement insertObject = [this]() {
312 return handle_.get().prepare(fmt::format(
313 R"(
314 INSERT INTO {}
315 (key, sequence, object)
316 VALUES (?, ?, ?)
317 )",
318 qualifiedTableName(settingsProvider_.get(), "objects")
319 ));
320 }();
321
322 PreparedStatement insertTransaction = [this]() {
323 return handle_.get().prepare(fmt::format(
324 R"(
325 INSERT INTO {}
326 (hash, ledger_sequence, date, transaction, metadata)
327 VALUES (?, ?, ?, ?, ?)
328 )",
329 qualifiedTableName(settingsProvider_.get(), "transactions")
330 ));
331 }();
332
333 PreparedStatement insertLedgerTransaction = [this]() {
334 return handle_.get().prepare(fmt::format(
335 R"(
336 INSERT INTO {}
337 (ledger_sequence, hash)
338 VALUES (?, ?)
339 )",
340 qualifiedTableName(settingsProvider_.get(), "ledger_transactions")
341 ));
342 }();
343
344 PreparedStatement insertSuccessor = [this]() {
345 return handle_.get().prepare(fmt::format(
346 R"(
347 INSERT INTO {}
348 (key, seq, next)
349 VALUES (?, ?, ?)
350 )",
351 qualifiedTableName(settingsProvider_.get(), "successor")
352 ));
353 }();
354
355 PreparedStatement insertDiff = [this]() {
356 return handle_.get().prepare(fmt::format(
357 R"(
358 INSERT INTO {}
359 (seq, key)
360 VALUES (?, ?)
361 )",
362 qualifiedTableName(settingsProvider_.get(), "diff")
363 ));
364 }();
365
366 PreparedStatement insertAccountTx = [this]() {
367 return handle_.get().prepare(fmt::format(
368 R"(
369 INSERT INTO {}
370 (account, seq_idx, hash)
371 VALUES (?, ?, ?)
372 )",
373 qualifiedTableName(settingsProvider_.get(), "account_tx")
374 ));
375 }();
376
377 PreparedStatement insertNFT = [this]() {
378 return handle_.get().prepare(fmt::format(
379 R"(
380 INSERT INTO {}
381 (token_id, sequence, owner, is_burned)
382 VALUES (?, ?, ?, ?)
383 )",
384 qualifiedTableName(settingsProvider_.get(), "nf_tokens")
385 ));
386 }();
387
388 PreparedStatement insertIssuerNFT = [this]() {
389 return handle_.get().prepare(fmt::format(
390 R"(
391 INSERT INTO {}
392 (issuer, taxon, token_id)
393 VALUES (?, ?, ?)
394 )",
395 qualifiedTableName(settingsProvider_.get(), "issuer_nf_tokens_v2")
396 ));
397 }();
398
399 PreparedStatement insertNFTURI = [this]() {
400 return handle_.get().prepare(fmt::format(
401 R"(
402 INSERT INTO {}
403 (token_id, sequence, uri)
404 VALUES (?, ?, ?)
405 )",
406 qualifiedTableName(settingsProvider_.get(), "nf_token_uris")
407 ));
408 }();
409
410 PreparedStatement insertNFTTx = [this]() {
411 return handle_.get().prepare(fmt::format(
412 R"(
413 INSERT INTO {}
414 (token_id, seq_idx, hash)
415 VALUES (?, ?, ?)
416 )",
417 qualifiedTableName(settingsProvider_.get(), "nf_token_transactions")
418 ));
419 }();
420
421 PreparedStatement insertMPTHolder = [this]() {
422 return handle_.get().prepare(fmt::format(
423 R"(
424 INSERT INTO {}
425 (mpt_id, holder)
426 VALUES (?, ?)
427 )",
428 qualifiedTableName(settingsProvider_.get(), "mp_token_holders")
429 ));
430 }();
431
432 PreparedStatement insertLedgerHeader = [this]() {
433 return handle_.get().prepare(fmt::format(
434 R"(
435 INSERT INTO {}
436 (sequence, header)
437 VALUES (?, ?)
438 )",
439 qualifiedTableName(settingsProvider_.get(), "ledgers")
440 ));
441 }();
442
443 PreparedStatement insertLedgerHash = [this]() {
444 return handle_.get().prepare(fmt::format(
445 R"(
446 INSERT INTO {}
447 (hash, sequence)
448 VALUES (?, ?)
449 )",
450 qualifiedTableName(settingsProvider_.get(), "ledger_hashes")
451 ));
452 }();
453
454 //
455 // Update (and "delete") queries
456 //
457
458 PreparedStatement updateLedgerRange = [this]() {
459 return handle_.get().prepare(fmt::format(
460 R"(
461 UPDATE {}
462 SET sequence = ?
463 WHERE is_latest = ?
464 IF sequence IN (?, null)
465 )",
466 qualifiedTableName(settingsProvider_.get(), "ledger_range")
467 ));
468 }();
469
470 PreparedStatement deleteLedgerRange = [this]() {
471 return handle_.get().prepare(fmt::format(
472 R"(
473 UPDATE {}
474 SET sequence = ?
475 WHERE is_latest = False
476 )",
477 qualifiedTableName(settingsProvider_.get(), "ledger_range")
478 ));
479 }();
480
481 PreparedStatement insertMigratorStatus = [this]() {
482 return handle_.get().prepare(fmt::format(
483 R"(
484 INSERT INTO {}
485 (migrator_name, status)
486 VALUES (?, ?)
487 )",
488 qualifiedTableName(settingsProvider_.get(), "migrator_status")
489 ));
490 }();
491
492 //
493 // Select queries
494 //
495
496 PreparedStatement selectSuccessor = [this]() {
497 return handle_.get().prepare(fmt::format(
498 R"(
499 SELECT next
500 FROM {}
501 WHERE key = ?
502 AND seq <= ?
503 ORDER BY seq DESC
504 LIMIT 1
505 )",
506 qualifiedTableName(settingsProvider_.get(), "successor")
507 ));
508 }();
509
510 PreparedStatement selectDiff = [this]() {
511 return handle_.get().prepare(fmt::format(
512 R"(
513 SELECT key
514 FROM {}
515 WHERE seq = ?
516 )",
517 qualifiedTableName(settingsProvider_.get(), "diff")
518 ));
519 }();
520
521 PreparedStatement selectObject = [this]() {
522 return handle_.get().prepare(fmt::format(
523 R"(
524 SELECT object, sequence
525 FROM {}
526 WHERE key = ?
527 AND sequence <= ?
528 ORDER BY sequence DESC
529 LIMIT 1
530 )",
531 qualifiedTableName(settingsProvider_.get(), "objects")
532 ));
533 }();
534
535 PreparedStatement selectTransaction = [this]() {
536 return handle_.get().prepare(fmt::format(
537 R"(
538 SELECT transaction, metadata, ledger_sequence, date
539 FROM {}
540 WHERE hash = ?
541 )",
542 qualifiedTableName(settingsProvider_.get(), "transactions")
543 ));
544 }();
545
546 PreparedStatement selectAllTransactionHashesInLedger = [this]() {
547 return handle_.get().prepare(fmt::format(
548 R"(
549 SELECT hash
550 FROM {}
551 WHERE ledger_sequence = ?
552 )",
553 qualifiedTableName(settingsProvider_.get(), "ledger_transactions")
554 ));
555 }();
556
557 PreparedStatement selectLedgerPageKeys = [this]() {
558 return handle_.get().prepare(fmt::format(
559 R"(
560 SELECT key
561 FROM {}
562 WHERE TOKEN(key) >= ?
563 AND sequence <= ?
564 PER PARTITION LIMIT 1
565 LIMIT ?
566 ALLOW FILTERING
567 )",
568 qualifiedTableName(settingsProvider_.get(), "objects")
569 ));
570 }();
571
572 PreparedStatement selectLedgerPage = [this]() {
573 return handle_.get().prepare(fmt::format(
574 R"(
575 SELECT object, key
576 FROM {}
577 WHERE TOKEN(key) >= ?
578 AND sequence <= ?
579 PER PARTITION LIMIT 1
580 LIMIT ?
581 ALLOW FILTERING
582 )",
583 qualifiedTableName(settingsProvider_.get(), "objects")
584 ));
585 }();
586
587 PreparedStatement getToken = [this]() {
588 return handle_.get().prepare(fmt::format(
589 R"(
590 SELECT TOKEN(key)
591 FROM {}
592 WHERE key = ?
593 LIMIT 1
594 )",
595 qualifiedTableName(settingsProvider_.get(), "objects")
596 ));
597 }();
598
599 PreparedStatement selectAccountTx = [this]() {
600 return handle_.get().prepare(fmt::format(
601 R"(
602 SELECT hash, seq_idx
603 FROM {}
604 WHERE account = ?
605 AND seq_idx < ?
606 LIMIT ?
607 )",
608 qualifiedTableName(settingsProvider_.get(), "account_tx")
609 ));
610 }();
611
612 PreparedStatement selectAccountFromBegining = [this]() {
613 return handle_.get().prepare(fmt::format(
614 R"(
615 SELECT account
616 FROM {}
617 WHERE token(account) > 0
618 PER PARTITION LIMIT 1
619 LIMIT ?
620 )",
621 qualifiedTableName(settingsProvider_.get(), "account_tx")
622 ));
623 }();
624
625 PreparedStatement selectAccountFromToken = [this]() {
626 return handle_.get().prepare(fmt::format(
627 R"(
628 SELECT account
629 FROM {}
630 WHERE token(account) > token(?)
631 PER PARTITION LIMIT 1
632 LIMIT ?
633 )",
634 qualifiedTableName(settingsProvider_.get(), "account_tx")
635 ));
636 }();
637
638 PreparedStatement selectAccountTxForward = [this]() {
639 return handle_.get().prepare(fmt::format(
640 R"(
641 SELECT hash, seq_idx
642 FROM {}
643 WHERE account = ?
644 AND seq_idx > ?
645 ORDER BY seq_idx ASC
646 LIMIT ?
647 )",
648 qualifiedTableName(settingsProvider_.get(), "account_tx")
649 ));
650 }();
651
652 PreparedStatement selectNFT = [this]() {
653 return handle_.get().prepare(fmt::format(
654 R"(
655 SELECT sequence, owner, is_burned
656 FROM {}
657 WHERE token_id = ?
658 AND sequence <= ?
659 ORDER BY sequence DESC
660 LIMIT 1
661 )",
662 qualifiedTableName(settingsProvider_.get(), "nf_tokens")
663 ));
664 }();
665
666 PreparedStatement selectNFTURI = [this]() {
667 return handle_.get().prepare(fmt::format(
668 R"(
669 SELECT uri
670 FROM {}
671 WHERE token_id = ?
672 AND sequence <= ?
673 ORDER BY sequence DESC
674 LIMIT 1
675 )",
676 qualifiedTableName(settingsProvider_.get(), "nf_token_uris")
677 ));
678 }();
679
680 PreparedStatement selectNFTTx = [this]() {
681 return handle_.get().prepare(fmt::format(
682 R"(
683 SELECT hash, seq_idx
684 FROM {}
685 WHERE token_id = ?
686 AND seq_idx < ?
687 ORDER BY seq_idx DESC
688 LIMIT ?
689 )",
690 qualifiedTableName(settingsProvider_.get(), "nf_token_transactions")
691 ));
692 }();
693
694 PreparedStatement selectNFTTxForward = [this]() {
695 return handle_.get().prepare(fmt::format(
696 R"(
697 SELECT hash, seq_idx
698 FROM {}
699 WHERE token_id = ?
700 AND seq_idx >= ?
701 ORDER BY seq_idx ASC
702 LIMIT ?
703 )",
704 qualifiedTableName(settingsProvider_.get(), "nf_token_transactions")
705 ));
706 }();
707
708 PreparedStatement selectNFTIDsByIssuer = [this]() {
709 return handle_.get().prepare(fmt::format(
710 R"(
711 SELECT token_id
712 FROM {}
713 WHERE issuer = ?
714 AND (taxon, token_id) > ?
715 ORDER BY taxon ASC, token_id ASC
716 LIMIT ?
717 )",
718 qualifiedTableName(settingsProvider_.get(), "issuer_nf_tokens_v2")
719 ));
720 }();
721
722 PreparedStatement selectNFTIDsByIssuerTaxon = [this]() {
723 return handle_.get().prepare(fmt::format(
724 R"(
725 SELECT token_id
726 FROM {}
727 WHERE issuer = ?
728 AND taxon = ?
729 AND token_id > ?
730 ORDER BY taxon ASC, token_id ASC
731 LIMIT ?
732 )",
733 qualifiedTableName(settingsProvider_.get(), "issuer_nf_tokens_v2")
734 ));
735 }();
736
737 PreparedStatement selectMPTHolders = [this]() {
738 return handle_.get().prepare(fmt::format(
739 R"(
740 SELECT holder
741 FROM {}
742 WHERE mpt_id = ?
743 AND holder > ?
744 ORDER BY holder ASC
745 LIMIT ?
746 )",
747 qualifiedTableName(settingsProvider_.get(), "mp_token_holders")
748 ));
749 }();
750
751 PreparedStatement selectLedgerByHash = [this]() {
752 return handle_.get().prepare(fmt::format(
753 R"(
754 SELECT sequence
755 FROM {}
756 WHERE hash = ?
757 LIMIT 1
758 )",
759 qualifiedTableName(settingsProvider_.get(), "ledger_hashes")
760 ));
761 }();
762
763 PreparedStatement selectLedgerBySeq = [this]() {
764 return handle_.get().prepare(fmt::format(
765 R"(
766 SELECT header
767 FROM {}
768 WHERE sequence = ?
769 )",
770 qualifiedTableName(settingsProvider_.get(), "ledgers")
771 ));
772 }();
773
774 PreparedStatement selectLatestLedger = [this]() {
775 return handle_.get().prepare(fmt::format(
776 R"(
777 SELECT sequence
778 FROM {}
779 WHERE is_latest = True
780 )",
781 qualifiedTableName(settingsProvider_.get(), "ledger_range")
782 ));
783 }();
784
785 PreparedStatement selectLedgerRange = [this]() {
786 return handle_.get().prepare(fmt::format(
787 R"(
788 SELECT sequence
789 FROM {}
790 WHERE is_latest in (True, False)
791 )",
792 qualifiedTableName(settingsProvider_.get(), "ledger_range")
793 ));
794 }();
795
796 PreparedStatement selectMigratorStatus = [this]() {
797 return handle_.get().prepare(fmt::format(
798 R"(
799 SELECT status
800 FROM {}
801 WHERE migrator_name = ?
802 )",
803 qualifiedTableName(settingsProvider_.get(), "migrator_status")
804 ));
805 }();
806 };
807
813 void
815 {
816 LOG(log_.info()) << "Preparing cassandra statements";
817 statements_ = std::make_unique<Statements>(settingsProvider_, handle);
818 LOG(log_.info()) << "Finished preparing statements";
819 }
820
826 std::unique_ptr<Statements> const&
828 {
829 return statements_;
830 }
831
832private:
833 std::unique_ptr<Statements> statements_{nullptr};
834};
835
836} // namespace data::cassandra
Represents a handle to the cassandra database cluster.
Definition Handle.hpp:46
Prepared statements holder.
Definition Schema.hpp:291
Statements(SettingsProviderType const &settingsProvider, Handle const &handle)
Construct a new Statements object.
Definition Schema.hpp:302
Manages the DB schema and provides access to prepared statements.
Definition Schema.hpp:55
Schema(SettingsProviderType const &settingsProvider)
Construct a new Schema object.
Definition Schema.hpp:65
void prepareStatements(Handle const &handle)
Recreates the prepared statements.
Definition Schema.hpp:814
std::unique_ptr< Statements > const & operator->() const
Provides access to statements.
Definition Schema.hpp:827
Represents a prepared statement on the DB side.
Definition Statement.hpp:155
A simple thread-safe logger for the channel specified in the constructor.
Definition Logger.hpp:110
Pump info(SourceLocationType const &loc=CURRENT_SRC_LOCATION) const
Interface for logging at Severity::NFO severity.
Definition Logger.cpp:205
This namespace implements a wrapper for the Cassandra C++ driver.
Definition Concepts.hpp:37
std::string qualifiedTableName(SettingsProviderType const &provider, std::string_view name)
Returns the table name qualified with the keyspace and table prefix.
Definition Schema.hpp:46