diff --git a/crates/bindings-csharp/BSATN.Runtime/QueryBuilder.cs b/crates/bindings-csharp/BSATN.Runtime/QueryBuilder.cs index efe193e0240..ff703367f22 100644 --- a/crates/bindings-csharp/BSATN.Runtime/QueryBuilder.cs +++ b/crates/bindings-csharp/BSATN.Runtime/QueryBuilder.cs @@ -81,6 +81,28 @@ public BoolExpr(string sql) public BoolExpr Not() => new($"(NOT {Sql})"); public override string ToString() => Sql; + + public static implicit operator BoolExpr(bool value) => new(value ? "TRUE" : "FALSE"); + + public static implicit operator BoolExpr(Col col) => col.Eq(true); + + public static implicit operator BoolExpr(IxCol col) => col.Eq(true); +} + +internal static class QueryPredicate +{ + internal static BoolExpr ToBoolExpr(object value) => + value switch + { + BoolExpr expr => expr, + Col col => col.Eq(true), + IxCol col => col.Eq(true), + bool b => new BoolExpr(b ? "TRUE" : "FALSE"), + _ => throw new ArgumentException( + $"Unsupported predicate type '{value.GetType().Name}'. Expected BoolExpr<{typeof(TRow).Name}> or a boolean column.", + nameof(value) + ), + }; } public readonly struct IxJoinEq @@ -126,18 +148,6 @@ public Col(string tableName, string columnName) public BoolExpr Gte(SqlLiteral value) => new($"({RefSql} >= {value.Sql})"); - public BoolExpr Lt(NullableCol other) => - new($"({RefSql} < {other.RefSql})"); - - public BoolExpr Lte(NullableCol other) => - new($"({RefSql} <= {other.RefSql})"); - - public BoolExpr Gt(NullableCol other) => - new($"({RefSql} > {other.RefSql})"); - - public BoolExpr Gte(NullableCol other) => - new($"({RefSql} >= {other.RefSql})"); - public BoolExpr Lt(Col other) => new($"({RefSql} < {other.RefSql})"); public BoolExpr Lte(Col other) => new($"({RefSql} <= {other.RefSql})"); @@ -149,47 +159,6 @@ public BoolExpr Gte(NullableCol other) => public override string ToString() => RefSql; } -public readonly struct NullableCol - where TValue : notnull -{ - private readonly string tableName; - private readonly string columnName; - - public NullableCol(string tableName, string columnName) - { - this.tableName = tableName; - this.columnName = columnName; - } - - internal string RefSql => - $"{SqlFormat.QuoteIdent(tableName)}.{SqlFormat.QuoteIdent(columnName)}"; - - public BoolExpr Eq(SqlLiteral value) => new($"({RefSql} = {value.Sql})"); - - public BoolExpr Eq(NullableCol other) => - new($"({RefSql} = {other.RefSql})"); - - public BoolExpr Eq(Col other) => new($"({RefSql} = {other.RefSql})"); - - public IxJoinEq Eq(IxCol other) => - new(RefSql, other.RefSql); - - public BoolExpr Neq(SqlLiteral value) => new($"({RefSql} <> {value.Sql})"); - - public BoolExpr Neq(NullableCol other) => - new($"({RefSql} <> {other.RefSql})"); - - public BoolExpr Lt(SqlLiteral value) => new($"({RefSql} < {value.Sql})"); - - public BoolExpr Lte(SqlLiteral value) => new($"({RefSql} <= {value.Sql})"); - - public BoolExpr Gt(SqlLiteral value) => new($"({RefSql} > {value.Sql})"); - - public BoolExpr Gte(SqlLiteral value) => new($"({RefSql} >= {value.Sql})"); - - public override string ToString() => RefSql; -} - public readonly struct IxCol where TValue : notnull { @@ -215,31 +184,6 @@ public IxJoinEq Eq(IxCol other) = public override string ToString() => RefSql; } -public readonly struct NullableIxCol - where TValue : notnull -{ - private readonly string tableName; - private readonly string columnName; - - public NullableIxCol(string tableName, string columnName) - { - this.tableName = tableName; - this.columnName = columnName; - } - - internal string RefSql => - $"{SqlFormat.QuoteIdent(tableName)}.{SqlFormat.QuoteIdent(columnName)}"; - - public BoolExpr Eq(SqlLiteral value) => new($"({RefSql} = {value.Sql})"); - - public IxJoinEq Eq(NullableIxCol other) => - new(RefSql, other.RefSql); - - public BoolExpr Neq(SqlLiteral value) => new($"({RefSql} <> {value.Sql})"); - - public override string ToString() => RefSql; -} - public sealed class Table : IQuery { private readonly string tableName; @@ -261,17 +205,19 @@ public Table(string tableName, TCols cols, TIxCols ixCols) public string ToSql() => $"SELECT * FROM {SqlFormat.QuoteIdent(tableName)}"; - public FromWhere Where(Func> predicate) => - new(this, predicate(cols)); + public FromWhere Where(Func predicate) => + new(this, QueryPredicate.ToBoolExpr(predicate(cols)!)); - public FromWhere Where(Func> predicate) => - new(this, predicate(cols, ixCols)); + public FromWhere Where( + Func predicate + ) => new(this, QueryPredicate.ToBoolExpr(predicate(cols, ixCols)!)); - public FromWhere Filter(Func> predicate) => + public FromWhere Filter(Func predicate) => Where(predicate); - public FromWhere Filter(Func> predicate) => - Where(predicate); + public FromWhere Filter( + Func predicate + ) => Where(predicate); public LeftSemiJoin LeftSemijoin< TRightRow, @@ -303,17 +249,20 @@ internal FromWhere(Table table, BoolExpr expr) this.expr = expr; } - public FromWhere Where(Func> predicate) => - new(table, expr.And(predicate(table.Cols))); + public FromWhere Where(Func predicate) => + new(table, expr.And(QueryPredicate.ToBoolExpr(predicate(table.Cols)!))); - public FromWhere Where(Func> predicate) => - new(table, expr.And(predicate(table.Cols, table.IxCols))); + public FromWhere Where( + Func predicate + ) => + new(table, expr.And(QueryPredicate.ToBoolExpr(predicate(table.Cols, table.IxCols)!))); - public FromWhere Filter(Func> predicate) => + public FromWhere Filter(Func predicate) => Where(predicate); - public FromWhere Filter(Func> predicate) => - Where(predicate); + public FromWhere Filter( + Func predicate + ) => Where(predicate); public string ToSql() => $"{table.ToSql()} WHERE {expr.Sql}"; @@ -403,6 +352,16 @@ public LeftSemiJoin< ); } + public LeftSemiJoin< + TLeftRow, + TLeftCols, + TLeftIxCols, + TRightRow, + TRightCols, + TRightIxCols + > Where(Func> predicate) => + Where(cols => predicate(cols).Eq(true)); + public LeftSemiJoin< TLeftRow, TLeftCols, @@ -412,6 +371,15 @@ public LeftSemiJoin< TRightIxCols > Filter(Func> predicate) => Where(predicate); + public LeftSemiJoin< + TLeftRow, + TLeftCols, + TLeftIxCols, + TRightRow, + TRightCols, + TRightIxCols + > Filter(Func> predicate) => Where(predicate); + public LeftSemiJoin< TLeftRow, TLeftCols, @@ -512,6 +480,16 @@ public RightSemiJoin< ); } + public RightSemiJoin< + TLeftRow, + TLeftCols, + TLeftIxCols, + TRightRow, + TRightCols, + TRightIxCols + > Where(Func> predicate) => + Where(cols => predicate(cols).Eq(true)); + public RightSemiJoin< TLeftRow, TLeftCols, @@ -521,6 +499,15 @@ public RightSemiJoin< TRightIxCols > Filter(Func> predicate) => Where(predicate); + public RightSemiJoin< + TLeftRow, + TLeftCols, + TLeftIxCols, + TRightRow, + TRightCols, + TRightIxCols + > Filter(Func> predicate) => Where(predicate); + public RightSemiJoin< TLeftRow, TLeftCols, @@ -571,48 +558,12 @@ public static BoolExpr Gt(this Col col, ReadOnlySpan Gte(this Col col, ReadOnlySpan value) => col.Gte(SqlLit.String(value)); - public static BoolExpr Eq( - this NullableCol col, - ReadOnlySpan value - ) => col.Eq(SqlLit.String(value)); - - public static BoolExpr Neq( - this NullableCol col, - ReadOnlySpan value - ) => col.Neq(SqlLit.String(value)); - - public static BoolExpr Lt( - this NullableCol col, - ReadOnlySpan value - ) => col.Lt(SqlLit.String(value)); - - public static BoolExpr Lte( - this NullableCol col, - ReadOnlySpan value - ) => col.Lte(SqlLit.String(value)); - - public static BoolExpr Gt( - this NullableCol col, - ReadOnlySpan value - ) => col.Gt(SqlLit.String(value)); - - public static BoolExpr Gte( - this NullableCol col, - ReadOnlySpan value - ) => col.Gte(SqlLit.String(value)); - public static BoolExpr Eq(this Col col, bool value) => col.Eq(SqlLit.Bool(value)); public static BoolExpr Neq(this Col col, bool value) => col.Neq(SqlLit.Bool(value)); - public static BoolExpr Eq(this NullableCol col, bool value) => - col.Eq(SqlLit.Bool(value)); - - public static BoolExpr Neq(this NullableCol col, bool value) => - col.Neq(SqlLit.Bool(value)); - public static BoolExpr Eq(this Col col, sbyte value) => col.Eq(SqlLit.Int(value)); @@ -631,24 +582,6 @@ public static BoolExpr Gt(this Col col, sbyte value) => public static BoolExpr Gte(this Col col, sbyte value) => col.Gte(SqlLit.Int(value)); - public static BoolExpr Eq(this NullableCol col, sbyte value) => - col.Eq(SqlLit.Int(value)); - - public static BoolExpr Neq(this NullableCol col, sbyte value) => - col.Neq(SqlLit.Int(value)); - - public static BoolExpr Lt(this NullableCol col, sbyte value) => - col.Lt(SqlLit.Int(value)); - - public static BoolExpr Lte(this NullableCol col, sbyte value) => - col.Lte(SqlLit.Int(value)); - - public static BoolExpr Gt(this NullableCol col, sbyte value) => - col.Gt(SqlLit.Int(value)); - - public static BoolExpr Gte(this NullableCol col, sbyte value) => - col.Gte(SqlLit.Int(value)); - public static BoolExpr Eq(this Col col, byte value) => col.Eq(SqlLit.Int(value)); @@ -667,24 +600,6 @@ public static BoolExpr Gt(this Col col, byte value) => public static BoolExpr Gte(this Col col, byte value) => col.Gte(SqlLit.Int(value)); - public static BoolExpr Eq(this NullableCol col, byte value) => - col.Eq(SqlLit.Int(value)); - - public static BoolExpr Neq(this NullableCol col, byte value) => - col.Neq(SqlLit.Int(value)); - - public static BoolExpr Lt(this NullableCol col, byte value) => - col.Lt(SqlLit.Int(value)); - - public static BoolExpr Lte(this NullableCol col, byte value) => - col.Lte(SqlLit.Int(value)); - - public static BoolExpr Gt(this NullableCol col, byte value) => - col.Gt(SqlLit.Int(value)); - - public static BoolExpr Gte(this NullableCol col, byte value) => - col.Gte(SqlLit.Int(value)); - public static BoolExpr Eq(this Col col, short value) => col.Eq(SqlLit.Int(value)); @@ -703,24 +618,6 @@ public static BoolExpr Gt(this Col col, short value) => public static BoolExpr Gte(this Col col, short value) => col.Gte(SqlLit.Int(value)); - public static BoolExpr Eq(this NullableCol col, short value) => - col.Eq(SqlLit.Int(value)); - - public static BoolExpr Neq(this NullableCol col, short value) => - col.Neq(SqlLit.Int(value)); - - public static BoolExpr Lt(this NullableCol col, short value) => - col.Lt(SqlLit.Int(value)); - - public static BoolExpr Lte(this NullableCol col, short value) => - col.Lte(SqlLit.Int(value)); - - public static BoolExpr Gt(this NullableCol col, short value) => - col.Gt(SqlLit.Int(value)); - - public static BoolExpr Gte(this NullableCol col, short value) => - col.Gte(SqlLit.Int(value)); - public static BoolExpr Eq(this Col col, ushort value) => col.Eq(SqlLit.Int(value)); @@ -739,24 +636,6 @@ public static BoolExpr Gt(this Col col, ushort value) public static BoolExpr Gte(this Col col, ushort value) => col.Gte(SqlLit.Int(value)); - public static BoolExpr Eq(this NullableCol col, ushort value) => - col.Eq(SqlLit.Int(value)); - - public static BoolExpr Neq(this NullableCol col, ushort value) => - col.Neq(SqlLit.Int(value)); - - public static BoolExpr Lt(this NullableCol col, ushort value) => - col.Lt(SqlLit.Int(value)); - - public static BoolExpr Lte(this NullableCol col, ushort value) => - col.Lte(SqlLit.Int(value)); - - public static BoolExpr Gt(this NullableCol col, ushort value) => - col.Gt(SqlLit.Int(value)); - - public static BoolExpr Gte(this NullableCol col, ushort value) => - col.Gte(SqlLit.Int(value)); - public static BoolExpr Eq(this Col col, int value) => col.Eq(SqlLit.Int(value)); @@ -775,24 +654,6 @@ public static BoolExpr Gt(this Col col, int value) => public static BoolExpr Gte(this Col col, int value) => col.Gte(SqlLit.Int(value)); - public static BoolExpr Eq(this NullableCol col, int value) => - col.Eq(SqlLit.Int(value)); - - public static BoolExpr Neq(this NullableCol col, int value) => - col.Neq(SqlLit.Int(value)); - - public static BoolExpr Lt(this NullableCol col, int value) => - col.Lt(SqlLit.Int(value)); - - public static BoolExpr Lte(this NullableCol col, int value) => - col.Lte(SqlLit.Int(value)); - - public static BoolExpr Gt(this NullableCol col, int value) => - col.Gt(SqlLit.Int(value)); - - public static BoolExpr Gte(this NullableCol col, int value) => - col.Gte(SqlLit.Int(value)); - public static BoolExpr Eq(this Col col, uint value) => col.Eq(SqlLit.Int(value)); @@ -811,24 +672,6 @@ public static BoolExpr Gt(this Col col, uint value) => public static BoolExpr Gte(this Col col, uint value) => col.Gte(SqlLit.Int(value)); - public static BoolExpr Eq(this NullableCol col, uint value) => - col.Eq(SqlLit.Int(value)); - - public static BoolExpr Neq(this NullableCol col, uint value) => - col.Neq(SqlLit.Int(value)); - - public static BoolExpr Lt(this NullableCol col, uint value) => - col.Lt(SqlLit.Int(value)); - - public static BoolExpr Lte(this NullableCol col, uint value) => - col.Lte(SqlLit.Int(value)); - - public static BoolExpr Gt(this NullableCol col, uint value) => - col.Gt(SqlLit.Int(value)); - - public static BoolExpr Gte(this NullableCol col, uint value) => - col.Gte(SqlLit.Int(value)); - public static BoolExpr Eq(this Col col, long value) => col.Eq(SqlLit.Int(value)); @@ -847,24 +690,6 @@ public static BoolExpr Gt(this Col col, long value) => public static BoolExpr Gte(this Col col, long value) => col.Gte(SqlLit.Int(value)); - public static BoolExpr Eq(this NullableCol col, long value) => - col.Eq(SqlLit.Int(value)); - - public static BoolExpr Neq(this NullableCol col, long value) => - col.Neq(SqlLit.Int(value)); - - public static BoolExpr Lt(this NullableCol col, long value) => - col.Lt(SqlLit.Int(value)); - - public static BoolExpr Lte(this NullableCol col, long value) => - col.Lte(SqlLit.Int(value)); - - public static BoolExpr Gt(this NullableCol col, long value) => - col.Gt(SqlLit.Int(value)); - - public static BoolExpr Gte(this NullableCol col, long value) => - col.Gte(SqlLit.Int(value)); - public static BoolExpr Eq(this Col col, ulong value) => col.Eq(SqlLit.Int(value)); @@ -883,24 +708,6 @@ public static BoolExpr Gt(this Col col, ulong value) => public static BoolExpr Gte(this Col col, ulong value) => col.Gte(SqlLit.Int(value)); - public static BoolExpr Eq(this NullableCol col, ulong value) => - col.Eq(SqlLit.Int(value)); - - public static BoolExpr Neq(this NullableCol col, ulong value) => - col.Neq(SqlLit.Int(value)); - - public static BoolExpr Lt(this NullableCol col, ulong value) => - col.Lt(SqlLit.Int(value)); - - public static BoolExpr Lte(this NullableCol col, ulong value) => - col.Lte(SqlLit.Int(value)); - - public static BoolExpr Gt(this NullableCol col, ulong value) => - col.Gt(SqlLit.Int(value)); - - public static BoolExpr Gte(this NullableCol col, ulong value) => - col.Gte(SqlLit.Int(value)); - public static BoolExpr Eq(this Col col, U128 value) => col.Eq(SqlLit.Int(value)); @@ -919,64 +726,24 @@ public static BoolExpr Gt(this Col col, U128 value) => public static BoolExpr Gte(this Col col, U128 value) => col.Gte(SqlLit.Int(value)); - public static BoolExpr Eq(this NullableCol col, U128 value) => - col.Eq(SqlLit.Int(value)); - - public static BoolExpr Neq(this NullableCol col, U128 value) => - col.Neq(SqlLit.Int(value)); - - public static BoolExpr Lt(this NullableCol col, U128 value) => - col.Lt(SqlLit.Int(value)); - - public static BoolExpr Lte(this NullableCol col, U128 value) => - col.Lte(SqlLit.Int(value)); - - public static BoolExpr Gt(this NullableCol col, U128 value) => - col.Gt(SqlLit.Int(value)); - - public static BoolExpr Gte(this NullableCol col, U128 value) => - col.Gte(SqlLit.Int(value)); - public static BoolExpr Eq(this Col col, Identity value) => col.Eq(SqlLit.Identity(value)); public static BoolExpr Neq(this Col col, Identity value) => col.Neq(SqlLit.Identity(value)); - public static BoolExpr Eq(this NullableCol col, Identity value) => - col.Eq(SqlLit.Identity(value)); - - public static BoolExpr Neq(this NullableCol col, Identity value) => - col.Neq(SqlLit.Identity(value)); - public static BoolExpr Eq(this Col col, ConnectionId value) => col.Eq(SqlLit.ConnectionId(value)); public static BoolExpr Neq(this Col col, ConnectionId value) => col.Neq(SqlLit.ConnectionId(value)); - public static BoolExpr Eq( - this NullableCol col, - ConnectionId value - ) => col.Eq(SqlLit.ConnectionId(value)); - - public static BoolExpr Neq( - this NullableCol col, - ConnectionId value - ) => col.Neq(SqlLit.ConnectionId(value)); - public static BoolExpr Eq(this Col col, Uuid value) => col.Eq(SqlLit.Uuid(value)); public static BoolExpr Neq(this Col col, Uuid value) => col.Neq(SqlLit.Uuid(value)); - public static BoolExpr Eq(this NullableCol col, Uuid value) => - col.Eq(SqlLit.Uuid(value)); - - public static BoolExpr Neq(this NullableCol col, Uuid value) => - col.Neq(SqlLit.Uuid(value)); - public static BoolExpr Eq(this IxCol col, ReadOnlySpan value) => col.Eq(SqlLit.String(value)); @@ -985,150 +752,72 @@ public static BoolExpr Neq( ReadOnlySpan value ) => col.Neq(SqlLit.String(value)); - public static BoolExpr Eq( - this NullableIxCol col, - ReadOnlySpan value - ) => col.Eq(SqlLit.String(value)); - - public static BoolExpr Neq( - this NullableIxCol col, - ReadOnlySpan value - ) => col.Neq(SqlLit.String(value)); - public static BoolExpr Eq(this IxCol col, bool value) => col.Eq(SqlLit.Bool(value)); public static BoolExpr Neq(this IxCol col, bool value) => col.Neq(SqlLit.Bool(value)); - public static BoolExpr Eq(this NullableIxCol col, bool value) => - col.Eq(SqlLit.Bool(value)); - - public static BoolExpr Neq(this NullableIxCol col, bool value) => - col.Neq(SqlLit.Bool(value)); - public static BoolExpr Eq(this IxCol col, sbyte value) => col.Eq(SqlLit.Int(value)); public static BoolExpr Neq(this IxCol col, sbyte value) => col.Neq(SqlLit.Int(value)); - public static BoolExpr Eq(this NullableIxCol col, sbyte value) => - col.Eq(SqlLit.Int(value)); - - public static BoolExpr Neq(this NullableIxCol col, sbyte value) => - col.Neq(SqlLit.Int(value)); - public static BoolExpr Eq(this IxCol col, byte value) => col.Eq(SqlLit.Int(value)); public static BoolExpr Neq(this IxCol col, byte value) => col.Neq(SqlLit.Int(value)); - public static BoolExpr Eq(this NullableIxCol col, byte value) => - col.Eq(SqlLit.Int(value)); - - public static BoolExpr Neq(this NullableIxCol col, byte value) => - col.Neq(SqlLit.Int(value)); - public static BoolExpr Eq(this IxCol col, short value) => col.Eq(SqlLit.Int(value)); public static BoolExpr Neq(this IxCol col, short value) => col.Neq(SqlLit.Int(value)); - public static BoolExpr Eq(this NullableIxCol col, short value) => - col.Eq(SqlLit.Int(value)); - - public static BoolExpr Neq(this NullableIxCol col, short value) => - col.Neq(SqlLit.Int(value)); - public static BoolExpr Eq(this IxCol col, ushort value) => col.Eq(SqlLit.Int(value)); public static BoolExpr Neq(this IxCol col, ushort value) => col.Neq(SqlLit.Int(value)); - public static BoolExpr Eq(this NullableIxCol col, ushort value) => - col.Eq(SqlLit.Int(value)); - - public static BoolExpr Neq(this NullableIxCol col, ushort value) => - col.Neq(SqlLit.Int(value)); - public static BoolExpr Eq(this IxCol col, int value) => col.Eq(SqlLit.Int(value)); public static BoolExpr Neq(this IxCol col, int value) => col.Neq(SqlLit.Int(value)); - public static BoolExpr Eq(this NullableIxCol col, int value) => - col.Eq(SqlLit.Int(value)); - - public static BoolExpr Neq(this NullableIxCol col, int value) => - col.Neq(SqlLit.Int(value)); - public static BoolExpr Eq(this IxCol col, uint value) => col.Eq(SqlLit.Int(value)); public static BoolExpr Neq(this IxCol col, uint value) => col.Neq(SqlLit.Int(value)); - public static BoolExpr Eq(this NullableIxCol col, uint value) => - col.Eq(SqlLit.Int(value)); - - public static BoolExpr Neq(this NullableIxCol col, uint value) => - col.Neq(SqlLit.Int(value)); - public static BoolExpr Eq(this IxCol col, long value) => col.Eq(SqlLit.Int(value)); public static BoolExpr Neq(this IxCol col, long value) => col.Neq(SqlLit.Int(value)); - public static BoolExpr Eq(this NullableIxCol col, long value) => - col.Eq(SqlLit.Int(value)); - - public static BoolExpr Neq(this NullableIxCol col, long value) => - col.Neq(SqlLit.Int(value)); - public static BoolExpr Eq(this IxCol col, ulong value) => col.Eq(SqlLit.Int(value)); public static BoolExpr Neq(this IxCol col, ulong value) => col.Neq(SqlLit.Int(value)); - public static BoolExpr Eq(this NullableIxCol col, ulong value) => - col.Eq(SqlLit.Int(value)); - - public static BoolExpr Neq(this NullableIxCol col, ulong value) => - col.Neq(SqlLit.Int(value)); - public static BoolExpr Eq(this IxCol col, U128 value) => col.Eq(SqlLit.Int(value)); public static BoolExpr Neq(this IxCol col, U128 value) => col.Neq(SqlLit.Int(value)); - public static BoolExpr Eq(this NullableIxCol col, U128 value) => - col.Eq(SqlLit.Int(value)); - - public static BoolExpr Neq(this NullableIxCol col, U128 value) => - col.Neq(SqlLit.Int(value)); - public static BoolExpr Eq(this IxCol col, Identity value) => col.Eq(SqlLit.Identity(value)); public static BoolExpr Neq(this IxCol col, Identity value) => col.Neq(SqlLit.Identity(value)); - public static BoolExpr Eq(this NullableIxCol col, Identity value) => - col.Eq(SqlLit.Identity(value)); - - public static BoolExpr Neq( - this NullableIxCol col, - Identity value - ) => col.Neq(SqlLit.Identity(value)); - public static BoolExpr Eq(this IxCol col, ConnectionId value) => col.Eq(SqlLit.ConnectionId(value)); @@ -1137,27 +826,11 @@ public static BoolExpr Neq( ConnectionId value ) => col.Neq(SqlLit.ConnectionId(value)); - public static BoolExpr Eq( - this NullableIxCol col, - ConnectionId value - ) => col.Eq(SqlLit.ConnectionId(value)); - - public static BoolExpr Neq( - this NullableIxCol col, - ConnectionId value - ) => col.Neq(SqlLit.ConnectionId(value)); - public static BoolExpr Eq(this IxCol col, Uuid value) => col.Eq(SqlLit.Uuid(value)); public static BoolExpr Neq(this IxCol col, Uuid value) => col.Neq(SqlLit.Uuid(value)); - - public static BoolExpr Eq(this NullableIxCol col, Uuid value) => - col.Eq(SqlLit.Uuid(value)); - - public static BoolExpr Neq(this NullableIxCol col, Uuid value) => - col.Neq(SqlLit.Uuid(value)); } internal static class SqlFormat diff --git a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#FFI.verified.cs b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#FFI.verified.cs index 881b9ad8989..a4bdb86fac4 100644 --- a/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#FFI.verified.cs +++ b/crates/bindings-csharp/Codegen.Tests/fixtures/diag/snapshots/Module#FFI.verified.cs @@ -105,10 +105,7 @@ public readonly partial struct QueryBuilder public readonly struct TestDefaultFieldValuesCols { - public readonly global::SpacetimeDB.NullableCol< - global::TestDefaultFieldValues, - int - > UniqueField; + public readonly global::SpacetimeDB.Col UniqueField; public readonly global::SpacetimeDB.Col< global::TestDefaultFieldValues, string @@ -127,14 +124,14 @@ public readonly struct TestDefaultFieldValuesCols public readonly global::SpacetimeDB.Col DefaultF32; public readonly global::SpacetimeDB.Col DefaultF64; public readonly global::SpacetimeDB.Col DefaultEnum; - public readonly global::SpacetimeDB.NullableCol< + public readonly global::SpacetimeDB.Col< global::TestDefaultFieldValues, MyStruct > DefaultNull; internal TestDefaultFieldValuesCols(string tableName) { - UniqueField = new global::SpacetimeDB.NullableCol( + UniqueField = new global::SpacetimeDB.Col( tableName, "UniqueField" ); @@ -198,10 +195,10 @@ internal TestDefaultFieldValuesCols(string tableName) tableName, "DefaultEnum" ); - DefaultNull = new global::SpacetimeDB.NullableCol< - global::TestDefaultFieldValues, - MyStruct - >(tableName, "DefaultNull"); + DefaultNull = new global::SpacetimeDB.Col( + tableName, + "DefaultNull" + ); } } @@ -599,10 +596,7 @@ public readonly partial struct QueryBuilder public readonly struct TestUniqueNotEquatableCols { - public readonly global::SpacetimeDB.NullableCol< - global::TestUniqueNotEquatable, - int - > UniqueField; + public readonly global::SpacetimeDB.Col UniqueField; public readonly global::SpacetimeDB.Col< global::TestUniqueNotEquatable, TestEnumWithExplicitValues @@ -610,7 +604,7 @@ public readonly struct TestUniqueNotEquatableCols internal TestUniqueNotEquatableCols(string tableName) { - UniqueField = new global::SpacetimeDB.NullableCol( + UniqueField = new global::SpacetimeDB.Col( tableName, "UniqueField" ); diff --git a/crates/bindings-csharp/Codegen.Tests/fixtures/server/snapshots/Module#FFI.verified.cs b/crates/bindings-csharp/Codegen.Tests/fixtures/server/snapshots/Module#FFI.verified.cs index addc736a618..c519fb9d7e0 100644 --- a/crates/bindings-csharp/Codegen.Tests/fixtures/server/snapshots/Module#FFI.verified.cs +++ b/crates/bindings-csharp/Codegen.Tests/fixtures/server/snapshots/Module#FFI.verified.cs @@ -248,14 +248,8 @@ public readonly struct PublicTableCols global::PublicTable, System.Collections.Generic.List > ListField; - public readonly global::SpacetimeDB.NullableCol< - global::PublicTable, - int - > NullableValueField; - public readonly global::SpacetimeDB.NullableCol< - global::PublicTable, - string - > NullableReferenceField; + public readonly global::SpacetimeDB.Col NullableValueField; + public readonly global::SpacetimeDB.Col NullableReferenceField; internal PublicTableCols(string tableName) { @@ -357,14 +351,14 @@ internal PublicTableCols(string tableName) global::PublicTable, System.Collections.Generic.List >(tableName, "ListField"); - NullableValueField = new global::SpacetimeDB.NullableCol( + NullableValueField = new global::SpacetimeDB.Col( tableName, "NullableValueField" ); - NullableReferenceField = new global::SpacetimeDB.NullableCol< - global::PublicTable, - string - >(tableName, "NullableReferenceField"); + NullableReferenceField = new global::SpacetimeDB.Col( + tableName, + "NullableReferenceField" + ); } } diff --git a/crates/bindings-csharp/Codegen/Module.cs b/crates/bindings-csharp/Codegen/Module.cs index 8c988c2d902..e9c0d0522e5 100644 --- a/crates/bindings-csharp/Codegen/Module.cs +++ b/crates/bindings-csharp/Codegen/Module.cs @@ -904,9 +904,7 @@ string ColDecl(ColumnDeclaration col) var typeName = col.Type.Name; var isNullable = typeName.EndsWith("?", StringComparison.Ordinal); var valueTypeName = isNullable ? typeName[..^1] : typeName; - var colType = isNullable - ? "global::SpacetimeDB.NullableCol" - : "global::SpacetimeDB.Col"; + var colType = isNullable ? "global::SpacetimeDB.Col" : "global::SpacetimeDB.Col"; return $"public readonly {colType}<{globalRowName}, {valueTypeName}> {col.Name};"; } @@ -915,9 +913,7 @@ string ColInit(ColumnDeclaration col) var typeName = col.Type.Name; var isNullable = typeName.EndsWith("?", StringComparison.Ordinal); var valueTypeName = isNullable ? typeName[..^1] : typeName; - var colType = isNullable - ? "global::SpacetimeDB.NullableCol" - : "global::SpacetimeDB.Col"; + var colType = isNullable ? "global::SpacetimeDB.Col" : "global::SpacetimeDB.Col"; return $"{col.Name} = new {colType}<{globalRowName}, {valueTypeName}>(tableName, \"{col.Name}\");"; } @@ -950,7 +946,7 @@ string IxColDecl(ColumnDeclaration col) var isNullable = typeName.EndsWith("?", StringComparison.Ordinal); var valueTypeName = isNullable ? typeName[..^1] : typeName; var colType = isNullable - ? "global::SpacetimeDB.NullableIxCol" + ? "global::SpacetimeDB.IxCol" : "global::SpacetimeDB.IxCol"; return $"public readonly {colType}<{globalRowName}, {valueTypeName}> {col.Name};"; } @@ -961,7 +957,7 @@ string IxColInit(ColumnDeclaration col) var isNullable = typeName.EndsWith("?", StringComparison.Ordinal); var valueTypeName = isNullable ? typeName[..^1] : typeName; var colType = isNullable - ? "global::SpacetimeDB.NullableIxCol" + ? "global::SpacetimeDB.IxCol" : "global::SpacetimeDB.IxCol"; return $"{col.Name} = new {colType}<{globalRowName}, {valueTypeName}>(tableName, \"{col.Name}\");"; } diff --git a/crates/bindings-typescript/src/lib/query.ts b/crates/bindings-typescript/src/lib/query.ts index 4519381904e..2d7bcf052c7 100644 --- a/crates/bindings-typescript/src/lib/query.ts +++ b/crates/bindings-typescript/src/lib/query.ts @@ -11,6 +11,7 @@ import type { TypeBuilder, } from './type_builders'; import type { Values } from './type_util'; +import type { Bool as SatsBool } from './algebraic_type_variants'; /** * Helper to get the set of table names. @@ -65,7 +66,7 @@ type From = RowTypedQuery< Readonly<{ toSql(): string; where( - predicate: (row: RowExpr) => BooleanExpr + predicate: (row: RowExpr) => PredicateExpr ): From; rightSemijoin( other: TableRef, @@ -93,7 +94,7 @@ type SemijoinBuilder = RowTypedQuery< Readonly<{ toSql(): string; where( - predicate: (row: RowExpr) => BooleanExpr + predicate: (row: RowExpr) => PredicateExpr ): SemijoinBuilder; /** @deprecated No longer needed — builder is already a valid query. */ build(): Query; @@ -120,7 +121,7 @@ class SemijoinImpl } where( - predicate: (row: RowExpr) => BooleanExpr + predicate: (row: RowExpr) => PredicateExpr ): SemijoinImpl { const nextSourceQuery = this.sourceQuery.where(predicate); return new SemijoinImpl( @@ -167,9 +168,9 @@ class FromBuilder ) {} where( - predicate: (row: RowExpr) => BooleanExpr + predicate: (row: RowExpr) => PredicateExpr ): FromBuilder { - const newCondition = predicate(this.table.cols); + const newCondition = normalizePredicateExpr(predicate(this.table.cols)); const nextWhere = this.whereClause ? this.whereClause.and(newCondition) : newCondition; @@ -308,7 +309,7 @@ class TableRefImpl } where( - predicate: (row: RowExpr) => BooleanExpr + predicate: (row: RowExpr) => PredicateExpr ): FromBuilder { return this.asFrom().where(predicate); } @@ -628,6 +629,11 @@ export type ValueExpr = | LiteralExpr | ColumnExprForValue; +type PredicateExpr = + | BooleanExpr + | ColumnExprForValue + | boolean; + type LiteralExpr = { type: 'literal'; value: Value; @@ -654,6 +660,24 @@ function normalizeValue(val: ValueInput): ValueExpr { return literal(val as LiteralValue); } +function normalizePredicateExpr( + value: PredicateExpr +): BooleanExpr { + if (value instanceof BooleanExpr) return value; + if (typeof value === 'boolean') { + return new BooleanExpr({ + type: 'eq', + left: literal(value), + right: literal(true), + }); + } + return new BooleanExpr({ + type: 'eq', + left: value as ValueExpr, + right: literal(true), + }); +} + type EqExpr = BooleanExpr
; type BooleanExprData
= ( diff --git a/crates/bindings-typescript/tests/query.test.ts b/crates/bindings-typescript/tests/query.test.ts index 033a07dde96..fe4996c1896 100644 --- a/crates/bindings-typescript/tests/query.test.ts +++ b/crates/bindings-typescript/tests/query.test.ts @@ -30,6 +30,7 @@ const personTable = table( id: t.identity(), name: t.string(), age: t.u32(), + active: t.bool(), } ); @@ -141,6 +142,13 @@ describe('TableScan.toSql', () => { ); }); + it('accepts boolean columns directly as where predicates', () => { + const qb = makeQueryBuilder(schemaDef); + const sql = toSql(qb.person.where(row => row.active).build()); + + expect(sql).toBe(`SELECT * FROM "person" WHERE "person"."active" = TRUE`); + }); + it('renders Identity literals using their hex form', () => { const qb = makeQueryBuilder(schemaDef); const identity = new Identity( diff --git a/crates/codegen/src/csharp.rs b/crates/codegen/src/csharp.rs index f40bf9148a0..e449f703181 100644 --- a/crates/codegen/src/csharp.rs +++ b/crates/codegen/src/csharp.rs @@ -659,7 +659,7 @@ impl Lang for Csharp<'_> { for (field_name, field_type) in &product_type.elements { let prop = field_name.deref().to_case(Case::Pascal); let (col_ty, ty) = match field_type { - AlgebraicTypeUse::Option(inner) => ("NullableCol", ty_fmt(module, inner).to_string()), + AlgebraicTypeUse::Option(inner) => ("Col", ty_fmt(module, inner).to_string()), _ => ("Col", ty_fmt(module, field_type).to_string()), }; writeln!( @@ -673,7 +673,7 @@ impl Lang for Csharp<'_> { for (field_name, field_type) in &product_type.elements { let prop = field_name.deref().to_case(Case::Pascal); let (col_ty, ty) = match field_type { - AlgebraicTypeUse::Option(inner) => ("NullableCol", ty_fmt(module, inner).to_string()), + AlgebraicTypeUse::Option(inner) => ("Col", ty_fmt(module, inner).to_string()), _ => ("Col", ty_fmt(module, field_type).to_string()), }; let col_name = field_name.deref(); @@ -694,7 +694,7 @@ impl Lang for Csharp<'_> { } let prop = field_name.deref().to_case(Case::Pascal); let (col_ty, ty) = match field_type { - AlgebraicTypeUse::Option(inner) => ("NullableIxCol", ty_fmt(module, inner).to_string()), + AlgebraicTypeUse::Option(inner) => ("IxCol", ty_fmt(module, inner).to_string()), _ => ("IxCol", ty_fmt(module, field_type).to_string()), }; writeln!( @@ -711,7 +711,7 @@ impl Lang for Csharp<'_> { } let prop = field_name.deref().to_case(Case::Pascal); let (col_ty, ty) = match field_type { - AlgebraicTypeUse::Option(inner) => ("NullableIxCol", ty_fmt(module, inner).to_string()), + AlgebraicTypeUse::Option(inner) => ("IxCol", ty_fmt(module, inner).to_string()), _ => ("IxCol", ty_fmt(module, field_type).to_string()), }; let col_name = field_name.deref(); diff --git a/crates/codegen/tests/snapshots/codegen__codegen_csharp.snap b/crates/codegen/tests/snapshots/codegen__codegen_csharp.snap index ca3a472b158..07f01edce6c 100644 --- a/crates/codegen/tests/snapshots/codegen__codegen_csharp.snap +++ b/crates/codegen/tests/snapshots/codegen__codegen_csharp.snap @@ -2035,11 +2035,11 @@ namespace SpacetimeDB public sealed class TestDCols { - public global::SpacetimeDB.NullableCol TestC { get; } + public global::SpacetimeDB.Col TestC { get; } public TestDCols(string tableName) { - TestC = new global::SpacetimeDB.NullableCol(tableName, "test_c"); + TestC = new global::SpacetimeDB.Col(tableName, "test_c"); } } diff --git a/crates/query-builder/src/expr.rs b/crates/query-builder/src/expr.rs index a17a035bcdf..d6fc2d41f5a 100644 --- a/crates/query-builder/src/expr.rs +++ b/crates/query-builder/src/expr.rs @@ -37,6 +37,28 @@ impl BoolExpr { } } +impl From> for BoolExpr { + fn from(col: Col) -> Self { + col.eq(true) + } +} + +impl From for BoolExpr { + fn from(value: bool) -> Self { + if value { + BoolExpr::Eq( + Operand::Literal(LiteralValue("TRUE".to_string())), + Operand::Literal(LiteralValue("TRUE".to_string())), + ) + } else { + BoolExpr::Eq( + Operand::Literal(LiteralValue("FALSE".to_string())), + Operand::Literal(LiteralValue("TRUE".to_string())), + ) + } + } +} + /// Trait for types that can be used as the right-hand side of a comparison with a column of type V /// in table T. /// diff --git a/crates/query-builder/src/join.rs b/crates/query-builder/src/join.rs index e38af5f0248..4a43529da27 100644 --- a/crates/query-builder/src/join.rs +++ b/crates/query-builder/src/join.rs @@ -141,11 +141,12 @@ impl Query for RightSemiJoin { // LeftSemiJoin where() operates on L impl LeftSemiJoin { - pub fn r#where(self, f: F) -> Self + pub fn r#where(self, f: F) -> Self where - F: Fn(&L::Cols) -> BoolExpr, + F: Fn(&L::Cols) -> E, + E: Into>, { - let extra = f(&L::cols(self.left_col.table_name())); + let extra = f(&L::cols(self.left_col.table_name())).into(); let new = match self.where_expr { Some(existing) => Some(existing.and(extra)), None => Some(extra), @@ -159,9 +160,10 @@ impl LeftSemiJoin { } // Filter is an alias for where - pub fn filter(self, f: F) -> Self + pub fn filter(self, f: F) -> Self where - F: Fn(&L::Cols) -> BoolExpr, + F: Fn(&L::Cols) -> E, + E: Into>, { self.r#where(f) } @@ -189,11 +191,12 @@ impl LeftSemiJoin { // RightSemiJoin where() operates on R impl RightSemiJoin { - pub fn r#where(self, f: F) -> Self + pub fn r#where(self, f: F) -> Self where - F: Fn(&R::Cols) -> BoolExpr, + F: Fn(&R::Cols) -> E, + E: Into>, { - let extra = f(&R::cols(self.right_col.table_name())); + let extra = f(&R::cols(self.right_col.table_name())).into(); let new = match self.right_where_expr { Some(existing) => Some(existing.and(extra)), None => Some(extra), @@ -208,9 +211,10 @@ impl RightSemiJoin { } // Filter is an alias for where - pub fn filter(self, f: F) -> Self + pub fn filter(self, f: F) -> Self where - F: Fn(&R::Cols) -> BoolExpr, + F: Fn(&R::Cols) -> E, + E: Into>, { self.r#where(f) } diff --git a/crates/query-builder/src/lib.rs b/crates/query-builder/src/lib.rs index 9b5382967c5..b8dd794d20b 100644 --- a/crates/query-builder/src/lib.rs +++ b/crates/query-builder/src/lib.rs @@ -51,6 +51,7 @@ mod tests { pub id: Col, pub name: Col, pub age: Col, + pub online: Col, } impl UserCols { fn new(table_name: &'static str) -> Self { @@ -58,6 +59,7 @@ mod tests { id: Col::new(table_name, "id"), name: Col::new(table_name, "name"), age: Col::new(table_name, "age"), + online: Col::new(table_name, "online"), } } } @@ -132,6 +134,13 @@ mod tests { assert_eq!(norm(q.sql()), norm(expected)); } + #[test] + fn test_where_bool_column_directly() { + let q = users().r#where(|c| c.online).build(); + let expected = r#"SELECT * FROM "users" WHERE ("users"."online" = TRUE)"#; + assert_eq!(norm(q.sql()), norm(expected)); + } + #[test] fn test_where_gte_lte() { let q = users().r#where(|c| c.age.gte(18)).r#where(|c| c.age.lte(30)).build(); diff --git a/crates/query-builder/src/table.rs b/crates/query-builder/src/table.rs index 3d9fb588d93..596b2741340 100644 --- a/crates/query-builder/src/table.rs +++ b/crates/query-builder/src/table.rs @@ -149,11 +149,12 @@ impl Table { RawQuery::new(format!(r#"SELECT * FROM "{}""#, self.table_name)) } - pub fn r#where(self, f: F) -> FromWhere + pub fn r#where(self, f: F) -> FromWhere where - F: Fn(&T::Cols) -> BoolExpr, + F: Fn(&T::Cols) -> E, + E: Into>, { - let expr = f(&T::cols(self.table_name)); + let expr = f(&T::cols(self.table_name)).into(); FromWhere { table_name: self.table_name, expr, @@ -161,20 +162,22 @@ impl Table { } // Filter is an alias for where - pub fn filter(self, f: F) -> FromWhere + pub fn filter(self, f: F) -> FromWhere where - F: Fn(&T::Cols) -> BoolExpr, + F: Fn(&T::Cols) -> E, + E: Into>, { self.r#where(f) } } impl FromWhere { - pub fn r#where(self, f: F) -> Self + pub fn r#where(self, f: F) -> Self where - F: Fn(&T::Cols) -> BoolExpr, + F: Fn(&T::Cols) -> E, + E: Into>, { - let extra = f(&T::cols(self.table_name)); + let extra = f(&T::cols(self.table_name)).into(); Self { table_name: self.table_name, expr: self.expr.and(extra), @@ -182,9 +185,10 @@ impl FromWhere { } // Filter is an alias for where - pub fn filter(self, f: F) -> Self + pub fn filter(self, f: F) -> Self where - F: Fn(&T::Cols) -> BoolExpr, + F: Fn(&T::Cols) -> E, + E: Into>, { self.r#where(f) } diff --git a/crates/smoketests/modules/views-query/src/lib.rs b/crates/smoketests/modules/views-query/src/lib.rs index 58758c4d50c..0bf4bf60636 100644 --- a/crates/smoketests/modules/views-query/src/lib.rs +++ b/crates/smoketests/modules/views-query/src/lib.rs @@ -52,14 +52,14 @@ fn init(ctx: &ReducerContext) { #[spacetimedb::view(accessor = online_users, public)] fn online_users(ctx: &ViewContext) -> impl Query { - ctx.from.user().r#where(|c| c.online.eq(true)) + ctx.from.user().r#where(|c| c.online) } #[spacetimedb::view(accessor = online_users_age, public)] fn online_users_age(ctx: &ViewContext) -> impl Query { ctx.from .user() - .r#where(|u| u.online.eq(true)) + .r#where(|u| u.online) .right_semijoin(ctx.from.person(), |u, p| u.identity.eq(p.identity)) } diff --git a/crates/smoketests/tests/smoketests/views.rs b/crates/smoketests/tests/smoketests/views.rs index bae4d4f8fd8..654c551625b 100644 --- a/crates/smoketests/tests/smoketests/views.rs +++ b/crates/smoketests/tests/smoketests/views.rs @@ -8,6 +8,7 @@ const playerState = table( { identity: t.identity().primaryKey(), name: t.string().unique(), + online: t.bool(), } ); @@ -26,13 +27,19 @@ export const all_players = spacetimedb.anonymousView( ctx => ctx.from.playerState ); +export const online_players = spacetimedb.anonymousView( + { public: true }, + t.array(playerState.rowType), + ctx => ctx.from.playerState.where(row => row.online) +); + export const insert_player_proc = spacetimedb.procedure( { name: t.string() }, t.unit(), (ctx, { name }) => { const sender = ctx.sender; ctx.withTx(tx => { - tx.db.playerState.insert({ name, identity: sender }); + tx.db.playerState.insert({ name, identity: sender, online: true }); }); return {}; } @@ -47,12 +54,13 @@ public static partial class Module public partial struct Table { public uint Value; + public bool Alive; } [Reducer] - public static void InsertValue(ReducerContext ctx, uint value) + public static void InsertValue(ReducerContext ctx, uint value, bool alive) { - ctx.Db.Table.Insert(new Table { Value = value }); + ctx.Db.Table.Insert(new Table { Value = value, Alive = alive }); } [View(Accessor = "all", Public = true)] @@ -64,7 +72,7 @@ public static partial class Module [View(Accessor = "some", Public = true)] public static IQuery
Some(ViewContext ctx) { - return ctx.From.Table().Where(Row => Row.Value.Eq(1)); + return ctx.From.Table().Where(Row => Row.Alive); } } "#; @@ -576,7 +584,7 @@ fn test_typescript_query_builder_view_query() { test.call("insert_player_proc", &["Alice"]).unwrap(); test.assert_sql( - "SELECT name FROM all_players", + "SELECT name FROM online_players", r#" name --------- "Alice""#, @@ -590,23 +598,14 @@ fn test_csharp_query_builder_view_query() { test.publish_csharp_module_source("views-csharp", "views-csharp", CS_VIEWS_QUERY_BUILDER_MODULE) .unwrap(); - test.call("insert_value", &["0"]).unwrap(); - test.call("insert_value", &["1"]).unwrap(); - test.call("insert_value", &["2"]).unwrap(); - - test.assert_sql( - "SELECT * FROM all", - r#" value -------- - 0 - 1 - 2"#, - ); + test.call("insert_value", &["0", "false"]).unwrap(); + test.call("insert_value", &["1", "true"]).unwrap(); + test.call("insert_value", &["2", "false"]).unwrap(); test.assert_sql( "SELECT * FROM some", - r#" value -------- - 1"#, + r#" value | alive +-------+------- + 1 | true"#, ); } diff --git a/sdks/csharp/examples~/regression-tests/client/module_bindings/Tables/NullStringNullable.g.cs b/sdks/csharp/examples~/regression-tests/client/module_bindings/Tables/NullStringNullable.g.cs index 47cff5f3450..1b073500dc5 100644 --- a/sdks/csharp/examples~/regression-tests/client/module_bindings/Tables/NullStringNullable.g.cs +++ b/sdks/csharp/examples~/regression-tests/client/module_bindings/Tables/NullStringNullable.g.cs @@ -40,12 +40,12 @@ internal NullStringNullableHandle(DbConnection conn) : base(conn) public sealed class NullStringNullableCols { public global::SpacetimeDB.Col Id { get; } - public global::SpacetimeDB.NullableCol Name { get; } + public global::SpacetimeDB.Col Name { get; } public NullStringNullableCols(string tableName) { Id = new global::SpacetimeDB.Col(tableName, "id"); - Name = new global::SpacetimeDB.NullableCol(tableName, "name"); + Name = new global::SpacetimeDB.Col(tableName, "name"); } } diff --git a/sdks/csharp/examples~/regression-tests/client/module_bindings/Tables/NullableVec.g.cs b/sdks/csharp/examples~/regression-tests/client/module_bindings/Tables/NullableVec.g.cs index 6a351db1456..6e9cc8ab2b0 100644 --- a/sdks/csharp/examples~/regression-tests/client/module_bindings/Tables/NullableVec.g.cs +++ b/sdks/csharp/examples~/regression-tests/client/module_bindings/Tables/NullableVec.g.cs @@ -40,12 +40,12 @@ internal NullableVecHandle(DbConnection conn) : base(conn) public sealed class NullableVecCols { public global::SpacetimeDB.Col Id { get; } - public global::SpacetimeDB.NullableCol Pos { get; } + public global::SpacetimeDB.Col Pos { get; } public NullableVecCols(string tableName) { Id = new global::SpacetimeDB.Col(tableName, "id"); - Pos = new global::SpacetimeDB.NullableCol(tableName, "pos"); + Pos = new global::SpacetimeDB.Col(tableName, "pos"); } } diff --git a/sdks/csharp/examples~/regression-tests/client/module_bindings/Tables/NullableVecView.g.cs b/sdks/csharp/examples~/regression-tests/client/module_bindings/Tables/NullableVecView.g.cs index 5042b4c41e7..1ce87380b54 100644 --- a/sdks/csharp/examples~/regression-tests/client/module_bindings/Tables/NullableVecView.g.cs +++ b/sdks/csharp/examples~/regression-tests/client/module_bindings/Tables/NullableVecView.g.cs @@ -28,12 +28,12 @@ internal NullableVecViewHandle(DbConnection conn) : base(conn) public sealed class NullableVecViewCols { public global::SpacetimeDB.Col Id { get; } - public global::SpacetimeDB.NullableCol Pos { get; } + public global::SpacetimeDB.Col Pos { get; } public NullableVecViewCols(string tableName) { Id = new global::SpacetimeDB.Col(tableName, "id"); - Pos = new global::SpacetimeDB.NullableCol(tableName, "pos"); + Pos = new global::SpacetimeDB.Col(tableName, "pos"); } } diff --git a/sdks/csharp/examples~/regression-tests/republishing/client/module_bindings/Tables/ExampleData.g.cs b/sdks/csharp/examples~/regression-tests/republishing/client/module_bindings/Tables/ExampleData.g.cs index 35090f1ee6c..67350f3aaf1 100644 --- a/sdks/csharp/examples~/regression-tests/republishing/client/module_bindings/Tables/ExampleData.g.cs +++ b/sdks/csharp/examples~/regression-tests/republishing/client/module_bindings/Tables/ExampleData.g.cs @@ -56,7 +56,7 @@ public sealed class ExampleDataCols public global::SpacetimeDB.Col DefaultF32 { get; } public global::SpacetimeDB.Col DefaultF64 { get; } public global::SpacetimeDB.Col DefaultEnum { get; } - public global::SpacetimeDB.NullableCol DefaultNull { get; } + public global::SpacetimeDB.Col DefaultNull { get; } public ExampleDataCols(string tableName) { @@ -77,7 +77,7 @@ public ExampleDataCols(string tableName) DefaultF32 = new global::SpacetimeDB.Col(tableName, "default_f_32"); DefaultF64 = new global::SpacetimeDB.Col(tableName, "default_f_64"); DefaultEnum = new global::SpacetimeDB.Col(tableName, "default_enum"); - DefaultNull = new global::SpacetimeDB.NullableCol(tableName, "default_null"); + DefaultNull = new global::SpacetimeDB.Col(tableName, "default_null"); } } diff --git a/sdks/csharp/tests~/QueryBuilderTests.cs b/sdks/csharp/tests~/QueryBuilderTests.cs index 6876c01ad1e..92174f3b551 100644 --- a/sdks/csharp/tests~/QueryBuilderTests.cs +++ b/sdks/csharp/tests~/QueryBuilderTests.cs @@ -40,30 +40,6 @@ public RowIxCols(string tableName) private static Table MakeTable(string tableName) => new(tableName, new RowCols(tableName), new RowIxCols(tableName)); - private sealed class RowNullableCols - { - public NullableCol Name { get; } - public NullableCol Age { get; } - - public RowNullableCols(string tableName) - { - Name = new NullableCol(tableName, "Name"); - Age = new NullableCol(tableName, "Age"); - } - } - - private sealed class RowNullableIxCols - { - public NullableIxCol Name { get; } - - public RowNullableIxCols(string tableName) - { - Name = new NullableIxCol(tableName, "Name"); - } - } - - private static Table MakeNullableTable(string tableName) => - new(tableName, new RowNullableCols(tableName), new RowNullableIxCols(tableName)); private sealed class LeftCols { @@ -111,31 +87,6 @@ private static Table MakeLeftTable(string tableNa private static Table MakeRightTable(string tableName) => new(tableName, new RightCols(tableName), new RightIxCols(tableName)); - private sealed class LeftNullableIxCols - { - public NullableIxCol Id { get; } - - public LeftNullableIxCols(string tableName) - { - Id = new NullableIxCol(tableName, "id"); - } - } - - private sealed class RightNullableIxCols - { - public NullableIxCol Uid { get; } - - public RightNullableIxCols(string tableName) - { - Uid = new NullableIxCol(tableName, "uid"); - } - } - - private static Table MakeLeftNullableIxTable(string tableName) => - new(tableName, new LeftCols(tableName), new LeftNullableIxCols(tableName)); - - private static Table MakeRightNullableIxTable(string tableName) => - new(tableName, new RightCols(tableName), new RightNullableIxCols(tableName)); [Fact] public void All_QuotesTableName() @@ -174,6 +125,14 @@ public void Where_Eq_Bool_FormatsAsTrueFalse() ); } + [Fact] + public void Where_BoolColumn_FormatsCorrectly() + { + var table = MakeTable("T"); + var sql = table.Where(c => c.IsAdmin.Eq(true)).ToSql(); + Assert.Equal("SELECT * FROM \"T\" WHERE (\"T\".\"IsAdmin\" = TRUE)", sql); + } + [Fact] public void Where_WithIxColsOverload_FormatsCorrectly() { @@ -275,22 +234,6 @@ public void LeftSemijoin_Build_FormatsCorrectly() ); } - [Fact] - public void Where_NullableCol_Eq_FormatsCorrectly() - { - var table = MakeNullableTable("T"); - var sql = table.Where(c => c.Name.Eq("x")).ToSql(); - Assert.Equal("SELECT * FROM \"T\" WHERE (\"T\".\"Name\" = 'x')", sql); - } - - [Fact] - public void Where_NullableCol_Gt_FormatsCorrectly() - { - var table = MakeNullableTable("T"); - var sql = table.Where(c => c.Age.Gt(123)).ToSql(); - Assert.Equal("SELECT * FROM \"T\" WHERE (\"T\".\"Age\" > 123)", sql); - } - [Fact] public void RightSemijoin_WithLeftAndRightWhere_FormatsCorrectly() { diff --git a/templates/chat-console-cs/module_bindings/Tables/User.g.cs b/templates/chat-console-cs/module_bindings/Tables/User.g.cs index 53d12b651ad..aa152f5c5a1 100644 --- a/templates/chat-console-cs/module_bindings/Tables/User.g.cs +++ b/templates/chat-console-cs/module_bindings/Tables/User.g.cs @@ -40,13 +40,13 @@ internal UserHandle(DbConnection conn) : base(conn) public sealed class UserCols { public global::SpacetimeDB.Col Identity { get; } - public global::SpacetimeDB.NullableCol Name { get; } + public global::SpacetimeDB.Col Name { get; } public global::SpacetimeDB.Col Online { get; } public UserCols(string tableName) { Identity = new global::SpacetimeDB.Col(tableName, "Identity"); - Name = new global::SpacetimeDB.NullableCol(tableName, "Name"); + Name = new global::SpacetimeDB.Col(tableName, "Name"); Online = new global::SpacetimeDB.Col(tableName, "Online"); } }