-
Notifications
You must be signed in to change notification settings - Fork 668
C# client typed query builder #3982
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
joshua-spacetime
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add some end-to-end tests?
| return new BoolExpr<TRow>($"{RefSql} = {SqlFormat.FormatLiteral(value)}"); | ||
| } | ||
|
|
||
| public BoolExpr<TRow> Neq(TValue value) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the rust builder it's ne
| public BoolExpr<TRow> IsNull() => new($"{RefSql} IS NULL"); | ||
| public BoolExpr<TRow> IsNotNull() => new($"{RefSql} IS NOT NULL"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These aren't supported in SpacetimeSQL
| IxCols = ixCols; | ||
| } | ||
|
|
||
| public Query<TRow> All() => new($"SELECT * FROM {SqlFormat.QuoteIdent(tableName)}"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think All is necessary.
| { | ||
| if (value is null) | ||
| { | ||
| return "NULL"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't support NULL.
| } | ||
|
|
||
| var t = value.GetType(); | ||
| if (t.IsEnum) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We also don't currently support enum comparisons
| public void All_QuotesTableName() | ||
| { | ||
| var table = MakeTable("My\"Table"); | ||
| Assert.Equal("SELECT * FROM \"My\"\"Table\"", table.All().Sql); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as earlier, we don't need All() here. We can just .toSql() the table ref directly.
| public void Where_Eq_Null_UsesIsNull() | ||
| { | ||
| var table = MakeTable("T"); | ||
| var sql = table.Where(c => c.Name.Eq(null!)).Sql; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should make Eq's arg not nullable.
| public void Where_Neq_Null_UsesIsNotNull() | ||
| { | ||
| var table = MakeTable("T"); | ||
| var sql = table.Where(c => c.Name.Neq(null!)).Sql; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same for all of the args
Description of Changes
This PR implements the C# client-side typed query builder, as assigned in #3759.
Key pieces:
sdks/csharp/src/QueryBuilder.cs):Query(wraps the generated SQL string)Table<TRow, TCols, TIxCols>(entry point forAll()/Where(...))Col<TRow, TValue>andIxCol<TRow, TValue>(typed column references)BoolExpr(typed boolean expression composition)SqlFormat)crates/codegen/src/csharp.rs) to generate:*Colsand*IxColshelper classes used by the typed query builder.QueryBuilderwith aFromaccessor for each table/view, producingTable<...>values.TypedSubscriptionBuilderwhich collectsQuery<TRow>.Sqlvalues and calls the existing subscription API.AddQuery(Func<QueryBuilder, Query> build)entry point offSubscriptionBuilder, mirroring the proposal’s Rust API.*Cols/*IxColshelpers are now named after the table/view accessor name (PascalCase) instead of the row type, since multiple tables/views can share the same row type (e.g. alias tables / views returning an existing product type).C# usage examples (mirroring the proposal’s Rust examples)
API and ABI breaking changes
None.
Expected complexity level and risk
2 - Low to moderate
Testing
dotnet test sdks/csharp/tests~/tests.csproj -c Releasesdks/csharp/tests~/QueryBuilderTests.cs) validating:strings,bools,enums, SpacetimeDB primitive types)NULLsemantics forEq/NeqAnd/Or/Not)