From 06b9167542f8634205049b15012c9e284d5af65f Mon Sep 17 00:00:00 2001 From: Quin Lynch Date: Wed, 17 Jan 2024 16:44:05 -0400 Subject: [PATCH] root writer and labels --- src/EdgeDB.Net.QueryBuilder/QueryBuilder.cs | 68 ++++++----- .../QueryNodes/ForNode.cs | 29 ++--- .../QueryNodes/GroupNode.cs | 2 +- .../QueryNodes/InsertNode.cs | 14 +-- .../QueryNodes/QueryNode.cs | 49 +++++--- .../QueryNodes/SelectNode.cs | 109 +++++++++++------- .../QueryNodes/UpdateNode.cs | 45 +++++--- .../QueryNodes/WithNode.cs | 26 ++--- .../QueryStringWriter.cs | 89 ++++++++++++-- .../MethodCallExpressionTranslator.cs | 5 +- 10 files changed, 278 insertions(+), 158 deletions(-) diff --git a/src/EdgeDB.Net.QueryBuilder/QueryBuilder.cs b/src/EdgeDB.Net.QueryBuilder/QueryBuilder.cs index e00bce7f..214731dd 100644 --- a/src/EdgeDB.Net.QueryBuilder/QueryBuilder.cs +++ b/src/EdgeDB.Net.QueryBuilder/QueryBuilder.cs @@ -202,9 +202,20 @@ private TNode AddNode(NodeContext context, bool autoGenerated = false, Qu /// /// A which is the current query this builder has constructed. /// - internal BuiltQuery InternalBuild(bool includeGlobalsInQuery = true, Action? preFinalizerModifier = null) + internal BuiltQuery InternalBuild(bool? includeGlobalsInQuery = true, Action? preFinalizerModifier = null) + { + var writer = new QueryStringWriter(); + + InternalBuild(writer, includeGlobalsInQuery, preFinalizerModifier); + + return new BuiltQuery(writer.Compile(_schemaInfo).ToString()) + { + Parameters = _queryVariables, Globals = _queryGlobals + }; + } + + internal void InternalBuild(QueryStringWriter writer, bool? includeGlobalsInQuery = true, Action? preFinalizerModifier = null) { - List query = new(); List> parameters = new(); var nodes = _nodes; @@ -215,11 +226,10 @@ internal BuiltQuery InternalBuild(bool includeGlobalsInQuery = true, Action= 0; i--) + for (var i = 0; i != nodes.Count; i++) { - var node = nodes[i]; - - var result = node.Build(); - - // add the nodes query string if its not null or empty. - if (!string.IsNullOrEmpty(result.Query)) - query.Add(result.Query); - - // add any parameters the node has. - parameters.Add(result.Parameters); + nodes[i].FinalizeQuery(writer); + parameters.Add(nodes[i].Builder.QueryVariables); } - // reverse our query string since we built our nodes in reverse. - query.Reverse(); + // // build each node starting at the last node. + // for (int i = nodes.Count - 1; i >= 0; i--) + // { + // var node = nodes[i]; + // + // var result = node.Build(); + // + // // add the nodes query string if its not null or empty. + // if (!string.IsNullOrEmpty(result.Query)) + // query.Add(result.Query); + // + // // add any parameters the node has. + // parameters.Add(result.Parameters); + // } + + // // reverse our query string since we built our nodes in reverse. + // query.Reverse(); // flatten our parameters into a single collection and make it distinct. var variables = parameters @@ -262,14 +278,14 @@ internal BuiltQuery InternalBuild(bool includeGlobalsInQuery = true, Action !variables.Any(x => x.Key == x.Key))); - // construct a built query with our query text, variables, and globals. - return new BuiltQuery(string.Join(' ', query)) - { - Parameters = variables - .ToDictionary(x => x.Key, x => x.Value), - - Globals = !includeGlobalsInQuery ? _queryGlobals : null - }; + // // construct a built query with our query text, variables, and globals. + // return new BuiltQuery(string.Join(' ', query)) + // { + // Parameters = variables + // .ToDictionary(x => x.Key, x => x.Value), + // + // Globals = !includeGlobalsInQuery ? _queryGlobals : null + // }; } /// diff --git a/src/EdgeDB.Net.QueryBuilder/QueryNodes/ForNode.cs b/src/EdgeDB.Net.QueryBuilder/QueryNodes/ForNode.cs index e8343204..39ce94dc 100644 --- a/src/EdgeDB.Net.QueryBuilder/QueryNodes/ForNode.cs +++ b/src/EdgeDB.Net.QueryBuilder/QueryNodes/ForNode.cs @@ -98,26 +98,21 @@ public override void FinalizeQuery(QueryStringWriter writer) ParseExpression(writer, _name, _jsonName, _json); // finalize and build our sub nodes - var iterator = SubNodes.Select(x => + writer.Wrapped(writer => { - x.SchemaInfo = SchemaInfo; - x.FinalizeQuery(); - - var builtNode = x.Build(); - - foreach (var variable in builtNode.Parameters) - SetVariable(variable.Key, variable.Value); - - // copy the globals & variables to the current builder - foreach (var global in x.ReferencedGlobals) - SetGlobal(global.Name, global.Value, global.Reference); + foreach (var node in SubNodes) + { + node.SchemaInfo = SchemaInfo; + node.FinalizeQuery(writer); - // we don't need to copy variables or nodes here since we did that in the parse step - return builtNode.Query; - }).Where(x => !string.IsNullOrEmpty(x)).Aggregate((x, y) => $"{x} {y}"); + foreach (var variable in node.Builder.QueryVariables) + SetVariable(variable.Key, variable.Value); - // append union statement's content - Writer.Append($"({iterator})"); + // copy the globals & variables to the current builder + foreach (var global in node.ReferencedGlobals) + SetGlobal(global.Name, global.Value, global.Reference); + } + }); } } } diff --git a/src/EdgeDB.Net.QueryBuilder/QueryNodes/GroupNode.cs b/src/EdgeDB.Net.QueryBuilder/QueryNodes/GroupNode.cs index 2e93bbac..1acf5393 100644 --- a/src/EdgeDB.Net.QueryBuilder/QueryNodes/GroupNode.cs +++ b/src/EdgeDB.Net.QueryBuilder/QueryNodes/GroupNode.cs @@ -12,7 +12,7 @@ public GroupNode(NodeBuilder builder) : base(builder) { } - public override void Visit() + public override void FinalizeQuery(QueryStringWriter writer) { throw new NotImplementedException(); } diff --git a/src/EdgeDB.Net.QueryBuilder/QueryNodes/InsertNode.cs b/src/EdgeDB.Net.QueryBuilder/QueryNodes/InsertNode.cs index b09c4818..d880f05a 100644 --- a/src/EdgeDB.Net.QueryBuilder/QueryNodes/InsertNode.cs +++ b/src/EdgeDB.Net.QueryBuilder/QueryNodes/InsertNode.cs @@ -224,13 +224,13 @@ public override void Visit() } /// - public override void FinalizeQuery() + public override void FinalizeQuery(QueryStringWriter writer) { - Writer.Append("insert ") + writer.Append("insert ") .Append(OperatingType.GetEdgeDBTypeName()) .Append(' '); - _shape.Build(Writer, SchemaInfo); + _shape.Build(writer, SchemaInfo); if (_autogenerateUnlessConflict) { @@ -241,17 +241,17 @@ public override void FinalizeQuery() if (!SchemaInfo.TryGetObjectInfo(OperatingType, out var typeInfo)) throw new NotSupportedException($"Could not find type info for {OperatingType}"); - Writer.Append(' '); - ConflictUtils.GenerateExclusiveConflictStatement(Writer, typeInfo, _elseStatement is not null); + writer.Append(' '); + ConflictUtils.GenerateExclusiveConflictStatement(writer, typeInfo, _elseStatement is not null); } if (_elseStatement is not null) - _elseStatement(Writer); + _elseStatement(writer); if (Context.SetAsGlobal && Context.GlobalName is not null) { SetGlobal(Context.GlobalName, new SubQuery(writer => writer - .Wrapped(Writer) + .Wrapped(writer) ), null); } } diff --git a/src/EdgeDB.Net.QueryBuilder/QueryNodes/QueryNode.cs b/src/EdgeDB.Net.QueryBuilder/QueryNodes/QueryNode.cs index 71623c74..06990618 100644 --- a/src/EdgeDB.Net.QueryBuilder/QueryNodes/QueryNode.cs +++ b/src/EdgeDB.Net.QueryBuilder/QueryNodes/QueryNode.cs @@ -200,28 +200,41 @@ protected void TranslateExpression(LambdaExpression root, Expression expression, internal void ReplaceSubqueryAsLiteral(QueryStringWriter writer, QueryGlobal global, Action compile) { - var index = writer.IndexOf(global.Name); + if (!writer.TryGetLabeled(global.Name, out var markers)) + return; - if (index is -1) - throw new InvalidOperationException("Global could not be found within the query string"); - - string? cached = null; - - while (index is not -1) + foreach (var marker in markers) { - if (cached is null) + marker.Replace(writer => { - var globalWriter = writer.GetPositionalWriter(index); - compile(global, globalWriter); - cached = globalWriter.ToString(); - } - else - { - writer.Insert(index, cached); - } - - index = writer.IndexOf(global.Name); + compile(global, writer); + }); } + + + + // var index = writer.IndexOf(global.Name); + // + // if (index is -1) + // throw new InvalidOperationException("Global could not be found within the query string"); + // + // string? cached = null; + // + // while (index is not -1) + // { + // if (cached is null) + // { + // var globalWriter = writer.GetPositionalWriter(index); + // compile(global, globalWriter); + // cached = globalWriter.ToString(); + // } + // else + // { + // writer.Insert(index, cached); + // } + // + // index = writer.IndexOf(global.Name); + // } } } } diff --git a/src/EdgeDB.Net.QueryBuilder/QueryNodes/SelectNode.cs b/src/EdgeDB.Net.QueryBuilder/QueryNodes/SelectNode.cs index fb18d4da..f0c8e069 100644 --- a/src/EdgeDB.Net.QueryBuilder/QueryNodes/SelectNode.cs +++ b/src/EdgeDB.Net.QueryBuilder/QueryNodes/SelectNode.cs @@ -16,6 +16,10 @@ namespace EdgeDB.QueryNodes /// internal class SelectNode : QueryNode { + private QueryStringWriter.Proxy? _filter; + private QueryStringWriter.Proxy? _limit; + private QueryStringWriter.Proxy? _offset; + private QueryStringWriter.Proxy? _orderBy; private SelectShape? _shape; /// @@ -58,8 +62,13 @@ public override void Visit() } /// - public override void FinalizeQuery() + public override void FinalizeQuery(QueryStringWriter writer) { + if(SubNodes.Count > 1) + { + throw new NotSupportedException("Got more than one child node for select statement (this is a bug)"); + } + // if parent is defined, our select logic was generated in the // visit step, we can just return out. if (SubNodes.Count == 1) @@ -68,74 +77,76 @@ public override void FinalizeQuery() // set introspection details & finalize node.SchemaInfo = SchemaInfo; - node.FinalizeQuery(); - var result = node.Build(); - var selectTarget = result.Query; - - if (string.IsNullOrEmpty(selectTarget)) + writer.Append($"select ").Wrapped(writer => { + var pos = writer.Position; + node.FinalizeQuery(writer); + + // no query was written? + if (pos != writer.Position) return; + if(node.Context.SetAsGlobal && !string.IsNullOrEmpty(node.Context.GlobalName)) { // wrap global name - selectTarget = node.Context.GlobalName; + writer.Append(node.Context.GlobalName); } else throw new InvalidOperationException($"Cannot resolve parent node {Parent}'s query"); - } - - Writer.Append($"select ({selectTarget})"); + }); // append the shape of the parents node operating type if we should include ours if (Context.IncludeShape && _shape is not null) { - _shape.Compile(Writer, (writer, expression) => + _shape.Compile(writer, (writer, expression) => { using var consumer = NodeTranslationContext.CreateContextConsumer(expression.Root); ExpressionTranslator.ContextualTranslate(expression.Expression, consumer, writer); }); } - - return; } - else if(SubNodes.Count > 1) - { - throw new NotSupportedException("Got more than one child node for select statement (this is a bug)"); - } - - if(!Context.IncludeShape) + else if(!Context.IncludeShape) { if (Context.Expression is not null) { - var writer = Writer.GetPositionalWriter(0) + var expressionWriter = writer.GetPositionalWriter(0) .Append("select "); if (Context.SelectName is not null) - writer.Append(Context.SelectName).Append(' '); + expressionWriter.Append(Context.SelectName).Append(' '); - TranslateExpression(Context.Expression, writer); + TranslateExpression(Context.Expression, expressionWriter); } else - Writer.Insert(0, $"select {Context.SelectName ?? OperatingType.GetEdgeDBTypeName()}"); - - return; + writer.Insert(0, $"select {Context.SelectName ?? OperatingType.GetEdgeDBTypeName()}"); } - - if (_shape is not null) + else if (_shape is not null) { - var writer = Writer.GetPositionalWriter(0) + var shapeWriter = writer.GetPositionalWriter(0) .Append("select "); if (!Context.IsFreeObject) - writer.Append(Context.SelectName ?? OperatingType.GetEdgeDBTypeName()); + shapeWriter.Append(Context.SelectName ?? OperatingType.GetEdgeDBTypeName()); - _shape.Compile(writer, (writer, expression) => + _shape.Compile(shapeWriter, (writer, expression) => { using var consumer = NodeTranslationContext.CreateContextConsumer(expression.Root); ExpressionTranslator.ContextualTranslate(expression.Expression, consumer, writer); }); } + + if (_filter is not null) + writer.Append(_filter); + + if (_orderBy is not null) + writer.Append(_orderBy); + + if (_offset is not null) + writer.Append(_offset); + + if (_limit is not null) + writer.Append(_limit); } /// @@ -144,8 +155,11 @@ public override void FinalizeQuery() /// The filter predicate to add. public void Filter(LambdaExpression expression) { - Writer.Append(" filter "); - TranslateExpression(expression, Writer); + _filter ??= writer => + { + writer.Append(" filter "); + TranslateExpression(expression, writer); + }; } /// @@ -160,12 +174,15 @@ public void OrderBy(bool asc, LambdaExpression selector, OrderByNullPlacement? n { var direction = asc ? "asc" : "desc"; - Writer.Append(" order by "); - TranslateExpression(selector, Writer); - Writer.Append(" ").Append(direction); + _orderBy ??= writer => + { + writer.Append(" order by "); + TranslateExpression(selector, writer); + writer.Append(" ").Append(direction); - if (nullPlacement.HasValue) - Writer.Append(nullPlacement.Value.ToString().ToLowerInvariant()); + if (nullPlacement.HasValue) + writer.Append(nullPlacement.Value.ToString().ToLowerInvariant()); + }; } /// @@ -174,7 +191,7 @@ public void OrderBy(bool asc, LambdaExpression selector, OrderByNullPlacement? n /// The number of elements to offset by. internal void Offset(long offset) { - Writer.Append(" offset ").Append(offset); + _offset ??= writer => writer.Append(" offset ").Append(offset); } /// @@ -183,8 +200,11 @@ internal void Offset(long offset) /// The expression returning the number of elements to offset by. internal void OffsetExpression(LambdaExpression exp) { - Writer.Append(" offset "); - TranslateExpression(exp, Writer); + _offset ??= writer => + { + writer.Append(" offset "); + TranslateExpression(exp, writer); + }; } /// @@ -193,7 +213,7 @@ internal void OffsetExpression(LambdaExpression exp) /// The number of element to limit to. internal void Limit(long limit) { - Writer.Append(" limit ").Append(limit); + _limit ??= writer => writer.Append(" limit ").Append(limit); } /// @@ -202,8 +222,11 @@ internal void Limit(long limit) /// The expression returning the number of elements to limit to. internal void LimitExpression(LambdaExpression exp) { - Writer.Append(" limit "); - TranslateExpression(exp, Writer); + _limit ??= writer => + { + writer.Append(" limit "); + TranslateExpression(exp, writer); + }; } } } diff --git a/src/EdgeDB.Net.QueryBuilder/QueryNodes/UpdateNode.cs b/src/EdgeDB.Net.QueryBuilder/QueryNodes/UpdateNode.cs index 4d04555a..1dc7d45c 100644 --- a/src/EdgeDB.Net.QueryBuilder/QueryNodes/UpdateNode.cs +++ b/src/EdgeDB.Net.QueryBuilder/QueryNodes/UpdateNode.cs @@ -12,31 +12,36 @@ namespace EdgeDB.QueryNodes /// internal class UpdateNode : QueryNode { + private QueryStringWriter.Proxy? _filter; + /// public UpdateNode(NodeBuilder builder) : base(builder) { } /// public override void Visit() + { + // set whether or not we need introspection based on our child queries + RequiresIntrospection = Context.ChildQueries.Any(x => x.Value.RequiresIntrospection); + } + + private void AppendUpdateStatement(QueryStringWriter writer) { // resolve and append the UPDATE ... statement - Writer.Append("update "); + writer.Append("update "); if (Context.Selector is not null) - TranslateExpression(Context.Selector, Writer); + TranslateExpression(Context.Selector, writer); else - Writer.Append(OperatingType.GetEdgeDBTypeName()); + writer.Append(OperatingType.GetEdgeDBTypeName()); - // set whether or not we need introspection based on our child queries - RequiresIntrospection = Context.ChildQueries.Any(x => x.Value.RequiresIntrospection); - } + // add filter clause + if (_filter is not null) + writer.Append(_filter); - /// - public override void FinalizeQuery() - { // add our 'set' statement to our translated update factory - Writer.Append($" set "); + writer.Append(" set "); - TranslateExpression(Context.UpdateExpression!, Writer); + TranslateExpression(Context.UpdateExpression!, writer); // throw if we dont have introspection data when a child requires it if (RequiresIntrospection && SchemaInfo is null) @@ -48,15 +53,20 @@ public override void FinalizeQuery() // sub query will be built with introspection by the with node. SetGlobal(child.Key, child.Value, null); } + } + /// + public override void FinalizeQuery(QueryStringWriter writer) + { // if the builder wants this node to be a global if (Context.SetAsGlobal && Context.GlobalName != null) { SetGlobal(Context.GlobalName, new SubQuery(writer => writer - .Wrapped(Writer) + .Wrapped(AppendUpdateStatement) ), null); - Writer.Clear(); } + else + AppendUpdateStatement(writer); } /// @@ -65,9 +75,12 @@ public override void FinalizeQuery() /// The filter predicate to add. public void Filter(LambdaExpression filter) { - // translate the filter and append it to our query text. - Writer.Append(" filter "); - TranslateExpression(filter, Writer); + _filter ??= writer => + { + // translate the filter and append it to our query text. + writer.Append(" filter "); + TranslateExpression(filter, writer); + }; } } } diff --git a/src/EdgeDB.Net.QueryBuilder/QueryNodes/WithNode.cs b/src/EdgeDB.Net.QueryBuilder/QueryNodes/WithNode.cs index 6485ad84..29f53b73 100644 --- a/src/EdgeDB.Net.QueryBuilder/QueryNodes/WithNode.cs +++ b/src/EdgeDB.Net.QueryBuilder/QueryNodes/WithNode.cs @@ -1,10 +1,4 @@ -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.Linq; using System.Linq.Expressions; -using System.Text; -using System.Threading.Tasks; namespace EdgeDB.QueryNodes { @@ -16,7 +10,7 @@ internal class WithNode : QueryNode /// public WithNode(NodeBuilder builder) : base(builder) { } - private bool TryReduceNode(QueryGlobal global) + private bool TryReduceNode(QueryStringWriter writer, QueryGlobal global) { // check if we can even flatten this global var builder = global.Value is IQueryBuilder a @@ -44,7 +38,7 @@ private bool TryReduceNode(QueryGlobal global) if (EdgeDBTypeUtils.IsLink(operatingType, out _, out _) && bannedTypes.Contains(operatingType)) continue; - node.ReplaceSubqueryAsLiteral(global, CompileGlobalValue); + node.ReplaceSubqueryAsLiteral(writer, global, CompileGlobalValue); count--; } @@ -52,36 +46,34 @@ private bool TryReduceNode(QueryGlobal global) } /// - public override void Visit() + public override void FinalizeQuery(QueryStringWriter writer) { if (Context.Values is null || !Context.Values.Any()) return; - var nodes = Context.Values.Where(x => !TryReduceNode(x)).ToArray(); + var nodes = Context.Values.Where(x => !TryReduceNode(writer, x)).ToArray(); if (!nodes.Any()) return; - Writer.Append("with "); + writer.Append("with "); for (var i = 0; i != nodes.Length; i++) { var global = nodes[i]; - Writer.Append(global.Name) + writer.Append(global.Name) .Append(" := "); - CompileGlobalValue(global); + CompileGlobalValue(global, writer); if (i + 1 < nodes.Length) - Writer.Append(", "); + writer.Append(", "); } } - private void CompileGlobalValue(QueryGlobal global, QueryStringWriter? writer = null) + private void CompileGlobalValue(QueryGlobal global, QueryStringWriter writer) { - writer ??= Writer; - // if its a query builder, build it and add it as a sub-query. if (global.Value is IQueryBuilder queryBuilder) { diff --git a/src/EdgeDB.Net.QueryBuilder/QueryStringWriter.cs b/src/EdgeDB.Net.QueryBuilder/QueryStringWriter.cs index c194e9d2..2e60e36b 100644 --- a/src/EdgeDB.Net.QueryBuilder/QueryStringWriter.cs +++ b/src/EdgeDB.Net.QueryBuilder/QueryStringWriter.cs @@ -1,4 +1,5 @@ using EdgeDB.Schema; +using System.Diagnostics.CodeAnalysis; using System.Text; namespace EdgeDB; @@ -65,7 +66,7 @@ public void WriteAt(QueryStringWriter writer, int index) else if(_str is not null) writer.Insert(index, _str); else if (_ch is not null) - writer.Insert(index, _ch); + writer.Insert(index, _ch.Value); else writer.Insert(index, _value); @@ -79,6 +80,36 @@ public void WriteAt(QueryStringWriter writer, int index) public static implicit operator Value(Proxy callback) => new(callback); } + public sealed class Marker + { + public int Position { get; private set; } + public int Size { get; } + + private readonly QueryStringWriter _writer; + + internal Marker(QueryStringWriter writer, int size, int position) + { + _writer = writer; + Size = size; + Position = position; + } + + internal void Update(int delta) + { + Position += delta; + } + + public void Replace(Value value) + { + _writer + .Remove(Position, Size) + .Insert(Position, value); + } + + public void Replace(Proxy value) + => Replace(new Value(value)); + } + private sealed class PositionedQueryStringWriter : QueryStringWriter { private int _position; @@ -110,6 +141,7 @@ protected override void WriteInternal(string str) } } + private readonly Dictionary> _labels; private readonly StringBuilder _builder; private readonly SortedList _chunks; @@ -121,24 +153,42 @@ public int Position public char this[int index] => _builder[index]; - public QueryStringWriter() - { - _builder = new(); - _chunks = new(); - } + public QueryStringWriter() : this(new()) + { } private QueryStringWriter(StringBuilder stringBuilder) { _builder = stringBuilder; _chunks = new(); + _chunks = new(); + _labels = new(); + } + + private void UpdateLabels(int pos, int sz) + { + foreach (var label in _labels.Values.SelectMany(x => x).Where(x => x.Position <= pos)) + { + label.Update(sz); + } } protected virtual void WriteInternal(char ch) - => _builder.Append(ch); + { + _builder.Append(ch); + UpdateLabels(Position - 1, 1); + } + protected virtual void WriteInternal(string str) - => _builder.Append(str); + { + var pos = Position; + _builder.Append(str); + UpdateLabels(pos, str.Length); + } - protected virtual void OnExternalWrite(int position, int length){} + protected virtual void OnExternalWrite(int position, int length) {} + + public QueryStringWriter Remove(int start, int count) + => _builder.Remove(start, count); public Value Val(object? value) => new(value); @@ -154,6 +204,20 @@ public QueryStringWriter GetPositionalWriter(int index = -1) return new PositionedQueryStringWriter(index, this); } + public QueryStringWriter Label(string name, Value value) + { + if (!_labels.TryGetValue(name, out var labels)) + _labels[name] = labels = new(); + + var pos = Position; + Append(value); + labels.Add(new Marker(this, Position - pos, pos)); + return this; + } + + public bool TryGetLabeled(string name, [NotNullWhen(true)] out List? markers) + => _labels.TryGetValue(name, out markers); + public int IndexOf(string value, bool ignoreCase = false, int startIndex = 0) { int index; @@ -212,6 +276,13 @@ public QueryStringWriter Insert(int index, string s) OnExternalWrite(index, s.Length); return this; } + + public QueryStringWriter Insert(int index, Value val) + { + val.WriteAt(this, index); + return this; + } + public QueryStringWriter Insert(int index, object? o) { if (o is null) diff --git a/src/EdgeDB.Net.QueryBuilder/Translators/Expressions/MethodCallExpressionTranslator.cs b/src/EdgeDB.Net.QueryBuilder/Translators/Expressions/MethodCallExpressionTranslator.cs index bda4cafa..c3b26df2 100644 --- a/src/EdgeDB.Net.QueryBuilder/Translators/Expressions/MethodCallExpressionTranslator.cs +++ b/src/EdgeDB.Net.QueryBuilder/Translators/Expressions/MethodCallExpressionTranslator.cs @@ -51,10 +51,7 @@ public override void Translate(MethodCallExpression expression, ExpressionContex // attempt to get the scalar type of the result of the method. if (!EdgeDBTypeUtils.TryGetScalarType(expression.Type, out var type)) { - if(expressionResult is IQueryBuilder) - - // add it is a global - writer.Append(context.GetOrAddGlobal(expression, new SubQuery())); + throw new InvalidOperationException("Expected a scalar type for "); } // return the variable name containing the result of the method.