diff --git a/examples/EdgeDB.Examples.CSharp/Examples/QueryBuilder.cs b/examples/EdgeDB.Examples.CSharp/Examples/QueryBuilder.cs index e63c8f54..f4361339 100644 --- a/examples/EdgeDB.Examples.CSharp/Examples/QueryBuilder.cs +++ b/examples/EdgeDB.Examples.CSharp/Examples/QueryBuilder.cs @@ -43,7 +43,7 @@ public async Task ExecuteAsync(EdgeDBClient client) private static async Task QueryBuilderDemo(EdgeDBClient client) { // Selecting a type with autogen shape - var query = QueryBuilder.Select().Build().Prettify(); + var query = QueryBuilder.Select().Compile().Prettify(); // Adding a filter, orderby, offset, and limit query = QueryBuilder @@ -52,19 +52,19 @@ private static async Task QueryBuilderDemo(EdgeDBClient client) .OrderByDesending(x => x.Name) .Offset(2) .Limit(10) - .Build() + .Compile() .Prettify(); // Specifying a shape query = QueryBuilder.Select(shape => shape .Explicitly(p => new { p.Name, p.Email, p.BestFriend }) - ).Build().Prettify(); + ).Compile().Prettify(); // selecting things that are not types query = QueryBuilder.SelectExpression(() => EdgeQL.Count(QueryBuilder.Select()) - ).Build().Prettify(); + ).Compile().Prettify(); // selecting 'free objects' query = QueryBuilder.SelectExpression(ctx => new @@ -73,7 +73,7 @@ private static async Task QueryBuilderDemo(EdgeDBClient client) MyNumber = 42, SeveralNumbers = new long[] { 1, 2, 3 }, People = ctx.SubQuery(QueryBuilder.Select()) - }).Build().Prettify(); + }).Compile().Prettify(); // Backlinks query = QueryBuilder.Select(shape => shape @@ -85,7 +85,7 @@ private static async Task QueryBuilderDemo(EdgeDBClient client) // you can pass in a string instead of an expression to select out a 'EdgeDBObject' type. ReferencedFriends = ctx.BackLink(x => x.Friends) }) - ).Build().Prettify(); + ).Compile().Prettify(); // With object variables query = QueryBuilder @@ -93,19 +93,19 @@ private static async Task QueryBuilderDemo(EdgeDBClient client) .SelectExpression(ctx => new { PassedName = ctx.Variables.Args.Value.Name, PassedEmail = ctx.Variables.Args.Value.Email - }).Build().Prettify(); + }).Compile().Prettify(); // Inserting a new type var person = new Person { Email = "example@example.com", Name = "example" }; - query = QueryBuilder.Insert(person).Build().Prettify(); + query = QueryBuilder.Insert(person).Compile().Prettify(); // Complex insert with links & dealing with conflicts query = (await QueryBuilder .Insert(new Person { BestFriend = person, Name = "example2", Email = "example2@example.com" }) .UnlessConflict() .ElseReturn() - .BuildAsync(client)) + .CompileAsync(client)) .Prettify(); // Manual conflicts @@ -113,7 +113,7 @@ private static async Task QueryBuilderDemo(EdgeDBClient client) .Insert(person) .UnlessConflictOn(x => x.Email) .ElseReturn() - .Build() + .Compile() .Prettify(); // Autogenerating unless conflict with introspection @@ -121,7 +121,7 @@ private static async Task QueryBuilderDemo(EdgeDBClient client) .Insert(person) .UnlessConflict() .ElseReturn() - .BuildAsync(client)) + .CompileAsync(client)) .Prettify(); // Bulk inserts @@ -138,7 +138,7 @@ private static async Task QueryBuilderDemo(EdgeDBClient client) var tquery = await QueryBuilder.For(data, x => QueryBuilder.Insert(x) - ).BuildAsync(client); + ).CompileAsync(client); // Else statements (upsert demo) query = (await QueryBuilder @@ -147,21 +147,21 @@ private static async Task QueryBuilderDemo(EdgeDBClient client) .Else(q => q.Update(old => new Person { Name = old!.Name!.ToLower() }) ) - .BuildAsync(client)) + .CompileAsync(client)) .Prettify(); // Updating a type query = QueryBuilder .Update(old => new Person { Name = "example new name" }) .Filter(x => x.Email == "example@example.com") - .Build() + .Compile() .Prettify(); // Deleting types query = QueryBuilder .Delete() .Filter(x => EdgeQL.ILike(x.Name, "e%")) - .Build() + .Compile() .Prettify(); } } diff --git a/src/EdgeDB.Net.QueryBuilder/Compiled/CompiledQuery.cs b/src/EdgeDB.Net.QueryBuilder/Compiled/CompiledQuery.cs new file mode 100644 index 00000000..5a00399d --- /dev/null +++ b/src/EdgeDB.Net.QueryBuilder/Compiled/CompiledQuery.cs @@ -0,0 +1,67 @@ +using System.Collections.Immutable; +using System.Text.RegularExpressions; + +namespace EdgeDB; + +public class CompiledQuery(string query, Dictionary? variables) +{ + public string Query { get; } = query; + + public IReadOnlyDictionary? Variables { get; } + = variables?.ToImmutableDictionary(); + + internal readonly Dictionary? RawVariables = variables; + + /// + /// Prettifies the query text. + /// + /// + /// This method uses a lot of regex and can be unreliable, if + /// you're using this in a production setting please use with care. + /// + /// A prettified version of . + public string Prettify() + { + // add newlines + var result = Regex.Replace(Query, @"({|\(|\)|}|,)", m => + { + switch (m.Groups[1].Value) + { + case "{" or "(" or ",": + if (m.Groups[1].Value == "{" && Query[m.Index + 1] == '}') + return m.Groups[1].Value; + + return $"{m.Groups[1].Value}\n"; + + default: + return $"{((m.Groups[1].Value == "}" && (Query[m.Index - 1] == '{' || Query[m.Index - 1] == '}')) ? "" : "\n")}{m.Groups[1].Value}{((Query.Length != m.Index + 1 && (Query[m.Index + 1] != ',')) ? "\n" : "")}"; + } + }).Trim().Replace("\n ", "\n"); + + // clean up newline func + result = Regex.Replace(result, "\n\n", m => "\n"); + + // add indentation + result = Regex.Replace(result, "^", m => + { + int indent = 0; + + foreach (var c in result[..m.Index]) + { + if (c is '(' or '{') + indent++; + if (c is ')' or '}') + indent--; + } + + var next = result.Length != m.Index ? result[m.Index] : '\0'; + + if (next is '}' or ')') + indent--; + + return "".PadLeft(indent * 2); + }, RegexOptions.Multiline); + + return result; + } +} diff --git a/src/EdgeDB.Net.QueryBuilder/Compiled/DebugCompiledQuery.cs b/src/EdgeDB.Net.QueryBuilder/Compiled/DebugCompiledQuery.cs new file mode 100644 index 00000000..730561f1 --- /dev/null +++ b/src/EdgeDB.Net.QueryBuilder/Compiled/DebugCompiledQuery.cs @@ -0,0 +1,12 @@ +namespace EdgeDB.Compiled; + +public sealed class DebugCompiledQuery : CompiledQuery +{ + + + internal DebugCompiledQuery(string query, Dictionary variablesInternal, QueryWriter writer) + : base(query, variablesInternal) + { + + } +} diff --git a/src/EdgeDB.Net.QueryBuilder/Extensions/QueryBuilderExtensions.cs b/src/EdgeDB.Net.QueryBuilder/Extensions/QueryBuilderExtensions.cs index 7493ee0e..4c2de571 100644 --- a/src/EdgeDB.Net.QueryBuilder/Extensions/QueryBuilderExtensions.cs +++ b/src/EdgeDB.Net.QueryBuilder/Extensions/QueryBuilderExtensions.cs @@ -19,7 +19,7 @@ public static void WriteTo(this IQueryBuilder source, QueryWriter writer, IQuery target.Globals.AddRange(source.Globals); - source.InternalBuild(writer, context); + source.CompileInternal(writer, context); } public static void WriteTo( @@ -38,7 +38,7 @@ public static void WriteTo( expressionContext.SetGlobal(global.Name, global.Value, global.Reference); } - source.InternalBuild(writer, compileContext); + source.CompileInternal(writer, compileContext); } public static void WriteTo(this IQueryBuilder source, QueryWriter writer, QueryNode node, CompileContext? compileContext = null) @@ -51,7 +51,7 @@ public static void WriteTo(this IQueryBuilder source, QueryWriter writer, QueryN node.Builder.QueryGlobals.AddRange(source.Globals); - source.InternalBuild(writer, compileContext); + source.CompileInternal(writer, compileContext); } } } diff --git a/src/EdgeDB.Net.QueryBuilder/Interfaces/IQueryBuilder.cs b/src/EdgeDB.Net.QueryBuilder/Interfaces/IQueryBuilder.cs index dd17910d..1b72b348 100644 --- a/src/EdgeDB.Net.QueryBuilder/Interfaces/IQueryBuilder.cs +++ b/src/EdgeDB.Net.QueryBuilder/Interfaces/IQueryBuilder.cs @@ -1,4 +1,5 @@ using EdgeDB.Builders; +using EdgeDB.Compiled; using EdgeDB.Interfaces; using EdgeDB.Interfaces.Queries; using EdgeDB.QueryNodes; @@ -298,38 +299,25 @@ public interface IQueryBuilder internal Dictionary Variables { get; } /// - /// Builds the current query. + /// Compiles the current query. /// /// /// If the query requires introspection please use - /// . + /// . /// /// - /// A . + /// A . /// - BuiltQuery Build(); + CompiledQuery Compile(); /// - /// Builds the current query asynchronously, allowing database introspection. + /// Compiles the current query asynchronously, allowing database introspection. /// /// The client to preform introspection with. /// A cancellation token to cancel the asynchronous operation. - /// A . - ValueTask BuildAsync(IEdgeDBQueryable edgedb, CancellationToken token = default); + /// A . + ValueTask CompileAsync(IEdgeDBQueryable edgedb, CancellationToken token = default); - /// - /// Builds the current query builder into its - /// form and excludes globals from the query text and puts them in - /// . - /// - /// - /// A modifier delegate to change nodes behaviour before the finalizer is called. - /// - /// - /// A which is the current query this builder has constructed. - /// - internal BuiltQuery BuildWithGlobals(Action? preFinalizerModifier = null); - - internal void InternalBuild(QueryWriter writer, CompileContext? context = null); + internal void CompileInternal(QueryWriter writer, CompileContext? context = null); } } diff --git a/src/EdgeDB.Net.QueryBuilder/Lexical/QueryWriter.cs b/src/EdgeDB.Net.QueryBuilder/Lexical/QueryWriter.cs index 6af8007f..fa44c2f3 100644 --- a/src/EdgeDB.Net.QueryBuilder/Lexical/QueryWriter.cs +++ b/src/EdgeDB.Net.QueryBuilder/Lexical/QueryWriter.cs @@ -26,13 +26,11 @@ public void Dispose() } } - public IReadOnlyDictionary> Markers - => _markers; + public readonly Dictionary> Markers; private readonly List _markersRef; private readonly LooseLinkedList _tokens; - private readonly Dictionary> _markers; private readonly List _observers = []; @@ -43,7 +41,7 @@ public IReadOnlyDictionary> Markers public QueryWriter() { _tokens = new(); - _markers = new(); + Markers = new(); _markersRef = new(); _track = null; } @@ -199,12 +197,12 @@ private void UpdateMarkers(int position, int delta) } public bool TryGetMarker(string name, [MaybeNullWhen(false)] out LinkedList markers) - => _markers.TryGetValue(name, out markers); + => Markers.TryGetValue(name, out markers); public QueryWriter Marker(MarkerType type, string name, in Value value) { - if (!_markers.TryGetValue(name, out var markers)) - _markers[name] = markers = new(); + if (!Markers.TryGetValue(name, out var markers)) + Markers[name] = markers = new(); var currentIndex = TailIndex; Append(in value, out var head); @@ -224,8 +222,8 @@ public QueryWriter Marker(MarkerType type, string name, params Value[] values) if (values.Length == 0) return this; - if (!_markers.TryGetValue(name, out var markers)) - _markers[name] = markers = new(); + if (!Markers.TryGetValue(name, out var markers)) + Markers[name] = markers = new(); var currentIndex = TailIndex; @@ -372,7 +370,7 @@ public StringBuilder Compile(StringBuilder? builder = null) public void Dispose() { - _markers.Clear(); + Markers.Clear(); _tokens.Clear(); _observers.Clear(); _markersRef.Clear(); diff --git a/src/EdgeDB.Net.QueryBuilder/QueryBuilder.cs b/src/EdgeDB.Net.QueryBuilder/QueryBuilder.cs index b1bb3dc0..4e18a50e 100644 --- a/src/EdgeDB.Net.QueryBuilder/QueryBuilder.cs +++ b/src/EdgeDB.Net.QueryBuilder/QueryBuilder.cs @@ -193,27 +193,23 @@ private TNode AddNode(NodeContext context, bool autoGenerated = false, Qu } /// - /// Builds the current query builder into its form. + /// Compiles the current query builder into its form. /// /// - /// A which is the current query this builder has constructed. + /// A . /// - internal BuiltQuery InternalBuild(CompileContext? context = null) + internal CompiledQuery CompileInternal(CompileContext? context = null) { context ??= new CompileContext(); using var writer = new QueryWriter(); - InternalBuild(writer, context); + CompileInternal(writer, context); - return new BuiltQuery(writer.Compile().ToString()) - { - Parameters = _queryVariables, - Globals = _queryGlobals - }; + return new CompiledQuery(writer.Compile().ToString(), _queryVariables); } - internal void InternalBuild(QueryWriter writer, CompileContext? context = null) + internal void CompileInternal(QueryWriter writer, CompileContext? context = null) { context ??= new(); @@ -268,24 +264,6 @@ internal void InternalBuild(QueryWriter writer, CompileContext? context = null) nodes = nodes.Prepend(with).ToList(); } - // // 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 .SelectMany(x => x) @@ -293,48 +271,31 @@ internal void InternalBuild(QueryWriter writer, CompileContext? context = null) // add any variables that might have been added by other builders in a sub-query context. variables = variables.Concat(_queryVariables.Where(x => !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 - // }; } /// - public BuiltQuery Build() - => InternalBuild(); + public CompiledQuery Compile() + => CompileInternal(); /// - public ValueTask BuildAsync(IEdgeDBQueryable edgedb, CancellationToken token = default) - => IntrospectAndBuildAsync(edgedb, token); - - /// - internal BuiltQuery BuildWithGlobals(Action? preFinalizerModifier = null) - => InternalBuild(new CompileContext() - { - IncludeGlobalsInQuery = false, - PreFinalizerModifier = preFinalizerModifier - }); + public ValueTask CompileAsync(IEdgeDBQueryable edgedb, CancellationToken token = default) + => IntrospectAndCompileAsync(edgedb, token); /// - /// Preforms introspection and then builds this query builder into a . + /// Preforms introspection and then compiles this query builder into a . /// /// The client to preform introspection with. /// A cancellation token to cancel the introspection query. /// - /// A ValueTask representing the (a)sync introspection and building operation. - /// The result is the built form of this query builder. + /// A ValueTask representing the (a)sync introspection and compiling operation. + /// The result is the compiled form of this query builder. /// - private async ValueTask IntrospectAndBuildAsync(IEdgeDBQueryable edgedb, CancellationToken token) + private async ValueTask IntrospectAndCompileAsync(IEdgeDBQueryable edgedb, CancellationToken token) { if (_nodes.Any(x => x.RequiresIntrospection) || _queryGlobals.Any(x => x.Value is SubQuery subQuery && subQuery.RequiresIntrospection)) _schemaInfo ??= await SchemaIntrospector.GetOrCreateSchemaIntrospectionAsync(edgedb, token).ConfigureAwait(false); - var result = Build(); + var result = Compile(); _nodes.Clear(); _queryGlobals.Clear(); @@ -585,30 +546,30 @@ private QueryBuilder Else(Func, async Task> IMultiCardinalityExecutable.ExecuteAsync(IEdgeDBQueryable edgedb, Capabilities? capabilities, CancellationToken token) { - var result = await IntrospectAndBuildAsync(edgedb, token).ConfigureAwait(false); - return await edgedb.QueryAsync(result.Query, result.Parameters, capabilities, token).ConfigureAwait(false); + var result = await IntrospectAndCompileAsync(edgedb, token).ConfigureAwait(false); + return await edgedb.QueryAsync(result.Query, result.RawVariables, capabilities, token).ConfigureAwait(false); } /// async Task ISingleCardinalityExecutable.ExecuteAsync(IEdgeDBQueryable edgedb, Capabilities? capabilities, CancellationToken token) { - var result = await IntrospectAndBuildAsync(edgedb, token).ConfigureAwait(false); - return await edgedb.QuerySingleAsync(result.Query, result.Parameters, capabilities, token).ConfigureAwait(false); + var result = await IntrospectAndCompileAsync(edgedb, token).ConfigureAwait(false); + return await edgedb.QuerySingleAsync(result.Query, result.RawVariables, capabilities, token).ConfigureAwait(false); } /// async Task IMultiCardinalityExecutable.ExecuteSingleAsync(IEdgeDBQueryable edgedb, Capabilities? capabilities, CancellationToken token) { - var result = await IntrospectAndBuildAsync(edgedb, token).ConfigureAwait(false); - return await edgedb.QuerySingleAsync(result.Query, result.Parameters, capabilities, token).ConfigureAwait(false); + var result = await IntrospectAndCompileAsync(edgedb, token).ConfigureAwait(false); + return await edgedb.QuerySingleAsync(result.Query, result.RawVariables, capabilities, token).ConfigureAwait(false); } /// async Task IMultiCardinalityExecutable.ExecuteRequiredSingleAsync(IEdgeDBQueryable edgedb, Capabilities? capabilities, CancellationToken token) { - var result = await IntrospectAndBuildAsync(edgedb, token).ConfigureAwait(false); - return await edgedb.QueryRequiredSingleAsync(result.Query, result.Parameters, capabilities, token).ConfigureAwait(false); + var result = await IntrospectAndCompileAsync(edgedb, token).ConfigureAwait(false); + return await edgedb.QueryRequiredSingleAsync(result.Query, result.RawVariables, capabilities, token).ConfigureAwait(false); } @@ -616,99 +577,11 @@ async Task IMultiCardinalityExecutable.ExecuteRequiredSingleAsync( IReadOnlyCollection IQueryBuilder.Nodes => _nodes; List IQueryBuilder.Globals => _queryGlobals; Dictionary IQueryBuilder.Variables => _queryVariables; - BuiltQuery IQueryBuilder.BuildWithGlobals(Action? preFinalizerModifier) => BuildWithGlobals(preFinalizerModifier); - void IQueryBuilder.InternalBuild(QueryWriter writer, CompileContext? context) => - InternalBuild(writer, context); + void IQueryBuilder.CompileInternal(QueryWriter writer, CompileContext? context) => + CompileInternal(writer, context); #endregion } - - /// - /// Represents a built query. - /// - [System.Diagnostics.DebuggerDisplay(@"{Query,nq}")] - public class BuiltQuery - { - /// - /// Gets the query text. - /// - public string Query { get; internal init; } - - /// - /// Gets a collection of parameters for the query. - /// - public IDictionary? Parameters { get; internal init; } - - /// - /// Gets a prettified version of this query. - /// - public string Pretty - => Prettify(); - - internal List? Globals { get; init; } - - /// - /// Creates a new built query. - /// - /// The query text. - internal BuiltQuery(string query) - { - Query = query; - } - - /// - /// Prettifies the query text. - /// - /// - /// This method uses alot of regex and can be unreliable, if - /// you're using this in a production setting please use with care. - /// - /// A prettified version of . - public string Prettify() - { - // add newlines - var result = Regex.Replace(Query, @"({|\(|\)|}|,)", m => - { - switch (m.Groups[1].Value) - { - case "{" or "(" or ",": - if (m.Groups[1].Value == "{" && Query[m.Index + 1] == '}') - return m.Groups[1].Value; - - return $"{m.Groups[1].Value}\n"; - - default: - return $"{((m.Groups[1].Value == "}" && (Query[m.Index - 1] == '{' || Query[m.Index - 1] == '}')) ? "" : "\n")}{m.Groups[1].Value}{((Query.Length != m.Index + 1 && (Query[m.Index + 1] != ',')) ? "\n" : "")}"; - } - }).Trim().Replace("\n ", "\n"); - - // clean up newline func - result = Regex.Replace(result, "\n\n", m => "\n"); - - // add indentation - result = Regex.Replace(result, "^", m => - { - int indent = 0; - - foreach (var c in result[..m.Index]) - { - if (c is '(' or '{') - indent++; - if (c is ')' or '}') - indent--; - } - - var next = result.Length != m.Index ? result[m.Index] : '\0'; - - if (next is '}' or ')') - indent--; - - return "".PadLeft(indent * 2); - }, RegexOptions.Multiline); - - return result; - } - } } diff --git a/src/EdgeDB.Net.QueryBuilder/Translators/Expressions/InitializationTranslator.cs b/src/EdgeDB.Net.QueryBuilder/Translators/Expressions/InitializationTranslator.cs index a9b6cf74..a1e47d83 100644 --- a/src/EdgeDB.Net.QueryBuilder/Translators/Expressions/InitializationTranslator.cs +++ b/src/EdgeDB.Net.QueryBuilder/Translators/Expressions/InitializationTranslator.cs @@ -15,24 +15,18 @@ internal static class InitializationTranslator { public static Dictionary PullInitializationExpression(Expression expression) { - if(expression is MemberInitExpression memberInit) + return expression switch { - return memberInit.Bindings.ToDictionary( - x => x.Member, + MemberInitExpression memberInit => memberInit.Bindings.ToDictionary(x => x.Member, x => x is not MemberAssignment assignment ? throw new InvalidOperationException($"Expected MemberAssignment, but got {x.GetType().Name}") - : assignment.Expression - ); - } - else if (expression is NewExpression newExpression) - { - if (newExpression.Members is null) - throw new NullReferenceException("New expression must contain arguments"); - - return newExpression.Members.Zip(newExpression.Arguments).ToDictionary(x => x.First, x => x.Second); - } - - throw new ArgumentException($"expression is not an initialization expression", nameof(expression)); + : assignment.Expression), + NewExpression {Members: null} => throw new NullReferenceException( + "New expression must contain arguments"), + NewExpression newExpression => newExpression.Members!.Zip(newExpression.Arguments) + .ToDictionary(x => x.First, x => x.Second), + _ => throw new ArgumentException($"expression is not an initialization expression", nameof(expression)) + }; } private static SubQuery? GenerateMultiLinkInserter(Type innerType, IEnumerable collection, ExpressionContext context) @@ -50,34 +44,14 @@ public static Dictionary PullInitializationExpression(Ex if (!collection.Any()) return null; - return new SubQuery((info, subQuery) => + return new SubQuery((info, writer) => { - var builder = new QueryBuilder(info); - - var builtQuery = builder + new QueryBuilder(info) .For(collection, x => QueryBuilder .Insert(x) .UnlessConflict() ) - .BuildWithGlobals(); - - if(builtQuery.Parameters is not null) - { - foreach (var param in builtQuery.Parameters) - { - context.SetVariable(param.Key, param.Value); - } - } - - if(builtQuery.Globals is not null) - { - foreach(var global in builtQuery.Globals) - { - context.SetGlobal(global.Name, global.Value, global.Reference); - } - } - - subQuery.Append(builtQuery.Query); + .WriteTo(writer, context); }); } diff --git a/src/EdgeDB.Net.QueryBuilder/Translators/Expressions/MethodCallExpressionTranslator.cs b/src/EdgeDB.Net.QueryBuilder/Translators/Expressions/MethodCallExpressionTranslator.cs index a8182979..44299af5 100644 --- a/src/EdgeDB.Net.QueryBuilder/Translators/Expressions/MethodCallExpressionTranslator.cs +++ b/src/EdgeDB.Net.QueryBuilder/Translators/Expressions/MethodCallExpressionTranslator.cs @@ -190,23 +190,10 @@ private static void TranslateToEdgeQL(MethodCallExpression expression, Expressio var builder = (IQueryBuilder)Expression.Lambda(expression.Arguments[0]).Compile().DynamicInvoke()!; - // build it and copy its globals & parameters to our builder - var result = builder.BuildWithGlobals(); + writer.Wrapped(writer => builder.WriteTo(writer, context)); - if (result.Parameters is not null) - foreach (var parameter in result.Parameters) - context.SetVariable(parameter.Key, parameter.Value); - - if (result.Globals is not null) - foreach (var global in result.Globals) - context.SetGlobal(global.Name, global.Value, global.Reference); - - writer - .Append('(') - .Append(result.Query) - .Append(')'); - } return; + } default: throw new NotImplementedException( $"{expression.Method.Name} does not have an implementation. This is a bug, please file a github issue with your query to reproduce this exception."); diff --git a/src/EdgeDB.Net.Queryable/Extensions/QueryableExtensions.cs b/src/EdgeDB.Net.Queryable/Extensions/QueryableExtensions.cs index b3c43226..b3773e2a 100644 --- a/src/EdgeDB.Net.Queryable/Extensions/QueryableExtensions.cs +++ b/src/EdgeDB.Net.Queryable/Extensions/QueryableExtensions.cs @@ -19,9 +19,9 @@ public static class QueryableExtensions var transient = queryable.Provider.ToTransient(); - var builtQuery = await transient.Compile().BuildAsync(client, token); + var builtQuery = await transient.Compile().CompileAsync(client, token); - return await client.QueryAsync(builtQuery.Query, builtQuery.Parameters, token: token); + return await client.QueryAsync(builtQuery.Query, builtQuery.RawVariables, token: token); } public static async Task ExecuteSingleAsync( @@ -34,9 +34,9 @@ public static class QueryableExtensions var transient = queryable.Provider.ToTransient(); - var builtQuery = await transient.Compile().BuildAsync(client, token); + var builtQuery = await transient.Compile().CompileAsync(client, token); - return await client.QuerySingleAsync(builtQuery.Query, builtQuery.Parameters, token: token); + return await client.QuerySingleAsync(builtQuery.Query, builtQuery.RawVariables, token: token); } } } diff --git a/src/EdgeDB.Net.Queryable/GenericlessQueryBuilder.cs b/src/EdgeDB.Net.Queryable/GenericlessQueryBuilder.cs index c89c6df4..ea723e31 100644 --- a/src/EdgeDB.Net.Queryable/GenericlessQueryBuilder.cs +++ b/src/EdgeDB.Net.Queryable/GenericlessQueryBuilder.cs @@ -369,14 +369,14 @@ public GenericlessQueryBuilder Else(Func IntrospectAndBuildAsync(IEdgeDBQueryable edgedb, CancellationToken token) + private async ValueTask IntrospectAndBuildAsync(IEdgeDBQueryable edgedb, CancellationToken token) { if (_nodes.Any(x => x.RequiresIntrospection) || _queryGlobals.Any(x => x.Value is SubQuery subQuery && subQuery.RequiresIntrospection)) _schemaInfo ??= await SchemaIntrospector.GetOrCreateSchemaIntrospectionAsync(edgedb, token) .ConfigureAwait(false); - var result = Build(); + var result = Compile(); _nodes.Clear(); _queryGlobals.Clear(); @@ -384,24 +384,21 @@ private async ValueTask IntrospectAndBuildAsync(IEdgeDBQueryable edg } /// - /// Builds the current query builder into its form. + /// Compiles the current query builder into its form. /// /// - /// A which is the current query this builder has constructed. + /// A . /// - internal BuiltQuery InternalBuild(CompileContext? context = null) + internal CompiledQuery CompileInternal(CompileContext? context = null) { var writer = new QueryWriter(); - InternalBuild(writer, context); + CompileInternal(writer, context); - return new BuiltQuery(writer.Compile().ToString()) - { - Parameters = _queryVariables, Globals = _queryGlobals - }; + return new CompiledQuery(writer.Compile().ToString(), _queryVariables); } - internal void InternalBuild(QueryWriter writer, CompileContext? context = null) + internal void CompileInternal(QueryWriter writer, CompileContext? context = null) { context ??= new(); @@ -482,21 +479,13 @@ internal void InternalBuild(QueryWriter writer, CompileContext? context = null) } /// - public BuiltQuery Build() - => InternalBuild(); + public CompiledQuery Compile() + => CompileInternal(); /// - public ValueTask BuildAsync(IEdgeDBQueryable edgedb, CancellationToken token = default) + public ValueTask CompileAsync(IEdgeDBQueryable edgedb, CancellationToken token = default) => IntrospectAndBuildAsync(edgedb, token); - /// - public BuiltQuery BuildWithGlobals(Action? preFinalizerModifier = null) - => InternalBuild(new CompileContext() - { - IncludeGlobalsInQuery = false, - PreFinalizerModifier = preFinalizerModifier - }); - #endregion #region IQueryBuilder @@ -510,8 +499,8 @@ List IQueryBuilder.Globals Dictionary IQueryBuilder.Variables => _queryVariables; - void IQueryBuilder.InternalBuild(QueryWriter writer, CompileContext? context) => - InternalBuild(writer, context); + void IQueryBuilder.CompileInternal(QueryWriter writer, CompileContext? context) => + CompileInternal(writer, context); #endregion }