Skip to content

Commit 346e2b2

Browse files
JasonAtClockworkrekhoffbfops
authored
Add C++ query builder (#4664)
# Description of Changes - Added a query builder for C++ module bindings - Added query-builder table/filter/join types - Added semijoin support with compile-time checks for lookup-table and indexed-field usage - Added support for returning query-builder queries from C++ views - Hooked query-builder metadata into the C++ table/view macros and V10 module-def path - Added test coverage for the new C++ query-builder behavior - Compile tests for pass/fail cases - SQL tests for generated query output - Added a C++ test module for view primary key coverage - **Update:** Switched the core to pass the columns and index-columns metadata with the table source for better client-side codegen to have some shared code between server + client. # API and ABI breaking changes - No intended API or ABI breaking changes - Adds a new public query-builder API to the C++ bindings - C++ views can now return query-builder query types in addition to materialized row results # Expected complexity level and risk 3 - Mostly contained to C++ bindings, but it touches macros, view registration/serialization, and module-def generation, so there are a few places where the pieces need to stay in sync. # Testing I've done end to end testing of I think every type as well as built some tests to confirm the SQL output. - [x] Run the C++ query-builder SQL tests [crates/bindings-cpp/tests/query-builder-compile/run_query_builder_compile_tests.sh] - [x] Smoke test a generated C++ module using query-builder views --------- Signed-off-by: Jason Larabie <jason@clockworklabs.io> Co-authored-by: Ryan <r.ekhoff@clockworklabs.io> Co-authored-by: Zeke Foppa <196249+bfops@users.noreply.github.com>
1 parent 7b7e6a3 commit 346e2b2

38 files changed

Lines changed: 2940 additions & 64 deletions

crates/bindings-cpp/include/spacetimedb.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@
138138

139139
// View context and macros
140140
#include "spacetimedb/view_macros.h"
141+
#include "spacetimedb/query_builder.h"
141142

142143
// =============================================================================
143144
// CONVENIENCE ALIASES AND COMPATIBILITY

crates/bindings-cpp/include/spacetimedb/client_visibility_filter.h

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#pragma once
22

3+
#include "spacetimedb/query_builder.h"
4+
35
#include <string>
46

57
namespace SpacetimeDB {
@@ -21,21 +23,33 @@ namespace SpacetimeDB {
2123
/// will be reported during `spacetime publish`, not at compile time.
2224
class Filter {
2325
private:
24-
const char* sql_text_;
26+
std::string sql_text_;
2527

2628
public:
2729
/// Create a SQL-based client visibility filter
2830
static Filter Sql(const char* sql) {
2931
return Filter(sql);
3032
}
3133

34+
/// Create a SQL-based client visibility filter from an owned string
35+
static Filter Sql(std::string sql) {
36+
return Filter(std::move(sql));
37+
}
38+
39+
/// Create a SQL-based client visibility filter from a typed query-builder value.
40+
template<query_builder::QueryLike TQuery>
41+
static Filter Sql(const TQuery& query) {
42+
return Filter(query.into_sql());
43+
}
44+
3245
/// Get the SQL text for this filter
33-
const char* sql_text() const {
46+
const std::string& sql_text() const {
3447
return sql_text_;
3548
}
3649

3750
private:
38-
explicit Filter(const char* sql) : sql_text_(sql) {}
51+
explicit Filter(const char* sql) : sql_text_(sql != nullptr ? sql : "") {}
52+
explicit Filter(std::string sql) : sql_text_(std::move(sql)) {}
3953
};
4054

41-
} // namespace SpacetimeDB
55+
} // namespace SpacetimeDB

crates/bindings-cpp/include/spacetimedb/internal/Module.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ class Module {
115115
public:
116116
// Registration support routed through the V10 module-definition builder.
117117
static void RegisterClientVisibilityFilter(const char* sql);
118+
static void RegisterClientVisibilityFilter(const std::string& sql);
118119
static void SetCaseConversionPolicy(CaseConversionPolicy policy);
119120
static void RegisterExplicitTableName(const std::string& source_name, const std::string& canonical_name);
120121
static void RegisterExplicitFunctionName(const std::string& source_name, const std::string& canonical_name);
@@ -152,6 +153,10 @@ class Module {
152153
static void RegisterClientVisibilityFilter(const char* sql) {
153154
Internal::Module::RegisterClientVisibilityFilter(sql);
154155
}
156+
157+
static void RegisterClientVisibilityFilter(const std::string& sql) {
158+
Internal::Module::RegisterClientVisibilityFilter(sql);
159+
}
155160

156161
// Module metadata (future extension)
157162
static void SetMetadata([[maybe_unused]] const char* name, [[maybe_unused]] const char* version) {

crates/bindings-cpp/include/spacetimedb/internal/v10_builder.h

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "autogen/RawRowLevelSecurityDefV9.g.h"
3535
#include "autogen/RawTypeDefV10.g.h"
3636
#include "field_registration.h"
37+
#include "../query_builder.h"
3738
#include "buffer_pool.h"
3839
#include "runtime_registration.h"
3940
#include "template_utils.h"
@@ -466,10 +467,14 @@ class V10Builder {
466467
[func](ViewContext& ctx, BytesSource args_source) -> std::vector<uint8_t> {
467468
(void)args_source;
468469
auto result = func(ctx);
469-
auto result_vec = view_result_to_vec(std::move(result));
470470
IterBuf buf = IterBuf::take();
471-
{
472-
bsatn::Writer writer(buf.get());
471+
bsatn::Writer writer(buf.get());
472+
if constexpr (query_builder::QueryBuilderReturn<ReturnType>) {
473+
writer.write_u8(1);
474+
bsatn::serialize(writer, result.into_sql());
475+
} else {
476+
writer.write_u8(0);
477+
auto result_vec = view_result_to_vec(std::move(result));
473478
bsatn::serialize(writer, result_vec);
474479
}
475480
return buf.release();
@@ -480,10 +485,14 @@ class V10Builder {
480485
[func](AnonymousViewContext& ctx, BytesSource args_source) -> std::vector<uint8_t> {
481486
(void)args_source;
482487
auto result = func(ctx);
483-
auto result_vec = view_result_to_vec(std::move(result));
484488
IterBuf buf = IterBuf::take();
485-
{
486-
bsatn::Writer writer(buf.get());
489+
bsatn::Writer writer(buf.get());
490+
if constexpr (query_builder::QueryBuilderReturn<ReturnType>) {
491+
writer.write_u8(1);
492+
bsatn::serialize(writer, result.into_sql());
493+
} else {
494+
writer.write_u8(0);
495+
auto result_vec = view_result_to_vec(std::move(result));
487496
bsatn::serialize(writer, result_vec);
488497
}
489498
return buf.release();
@@ -492,8 +501,17 @@ class V10Builder {
492501
}
493502

494503
auto& type_reg = getModuleTypeRegistration();
495-
auto bsatn_return = bsatn::bsatn_traits<ReturnType>::algebraic_type();
496-
AlgebraicType return_type = type_reg.registerType(bsatn_return, "", &typeid(ReturnType));
504+
AlgebraicType return_type = [&]() {
505+
if constexpr (query_builder::QueryBuilderReturn<ReturnType>) {
506+
using RowType = query_builder::query_row_type_t<ReturnType>;
507+
auto row_bsatn = bsatn::bsatn_traits<RowType>::algebraic_type();
508+
auto row_type = type_reg.registerType(row_bsatn, "", &typeid(RowType));
509+
return MakeQueryReturnAlgebraicType(std::move(row_type));
510+
} else {
511+
auto bsatn_return = bsatn::bsatn_traits<ReturnType>::algebraic_type();
512+
return type_reg.registerType(bsatn_return, "", &typeid(ReturnType));
513+
}
514+
}();
497515
bool is_anonymous = std::is_same_v<ContextType, AnonymousViewContext>;
498516
uint32_t index = static_cast<uint32_t>(is_anonymous ? (GetAnonymousViewHandlerCount() - 1) : (GetViewHandlerCount() - 1));
499517

@@ -658,6 +676,7 @@ class V10Builder {
658676
uint16_t field_idx) const;
659677
static AlgebraicType MakeUnitAlgebraicType();
660678
static AlgebraicType MakeStringAlgebraicType();
679+
static AlgebraicType MakeQueryReturnAlgebraicType(AlgebraicType row_type);
661680

662681
std::vector<std::pair<std::string, bool>> table_is_event_;
663682
std::optional<CaseConversionPolicy> case_conversion_policy_;

0 commit comments

Comments
 (0)