Skip to content

Commit

Permalink
Build -> Compile
Browse files Browse the repository at this point in the history
  • Loading branch information
quinchs committed Mar 9, 2024
1 parent 2451099 commit 975f2c6
Show file tree
Hide file tree
Showing 11 changed files with 170 additions and 282 deletions.
30 changes: 15 additions & 15 deletions examples/EdgeDB.Examples.CSharp/Examples/QueryBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Person>().Build().Prettify();
var query = QueryBuilder.Select<Person>().Compile().Prettify();

// Adding a filter, orderby, offset, and limit
query = QueryBuilder
Expand All @@ -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<Person>(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<Person>())
).Build().Prettify();
).Compile().Prettify();

// selecting 'free objects'
query = QueryBuilder.SelectExpression(ctx => new
Expand All @@ -73,7 +73,7 @@ private static async Task QueryBuilderDemo(EdgeDBClient client)
MyNumber = 42,
SeveralNumbers = new long[] { 1, 2, 3 },
People = ctx.SubQuery(QueryBuilder.Select<Person>())
}).Build().Prettify();
}).Compile().Prettify();

// Backlinks
query = QueryBuilder.Select<Person>(shape => shape
Expand All @@ -85,43 +85,43 @@ 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<Person>(x => x.Friends)
})
).Build().Prettify();
).Compile().Prettify();

// With object variables
query = QueryBuilder
.With(new { Args = EdgeQL.AsJson(new { Name = "Example", Email = "[email protected]" }) })
.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 = "[email protected]", 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 = "[email protected]" })
.UnlessConflict()
.ElseReturn()
.BuildAsync(client))
.CompileAsync(client))
.Prettify();

// Manual conflicts
query = QueryBuilder
.Insert(person)
.UnlessConflictOn(x => x.Email)
.ElseReturn()
.Build()
.Compile()
.Prettify();

// Autogenerating unless conflict with introspection
query = (await QueryBuilder
.Insert(person)
.UnlessConflict()
.ElseReturn()
.BuildAsync(client))
.CompileAsync(client))
.Prettify();

// Bulk inserts
Expand All @@ -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
Expand All @@ -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<Person>(old => new Person { Name = "example new name" })
.Filter(x => x.Email == "[email protected]")
.Build()
.Compile()
.Prettify();

// Deleting types
query = QueryBuilder
.Delete<Person>()
.Filter(x => EdgeQL.ILike(x.Name, "e%"))
.Build()
.Compile()
.Prettify();
}
}
Expand Down
67 changes: 67 additions & 0 deletions src/EdgeDB.Net.QueryBuilder/Compiled/CompiledQuery.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System.Collections.Immutable;
using System.Text.RegularExpressions;

namespace EdgeDB;

public class CompiledQuery(string query, Dictionary<string, object?>? variables)
{
public string Query { get; } = query;

public IReadOnlyDictionary<string, object?>? Variables { get; }
= variables?.ToImmutableDictionary();

internal readonly Dictionary<string, object?>? RawVariables = variables;

/// <summary>
/// Prettifies the query text.
/// </summary>
/// <remarks>
/// This method uses a lot of regex and can be unreliable, if
/// you're using this in a production setting please use with care.
/// </remarks>
/// <returns>A prettified version of <see cref="Query"/>.</returns>
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;
}
}
12 changes: 12 additions & 0 deletions src/EdgeDB.Net.QueryBuilder/Compiled/DebugCompiledQuery.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace EdgeDB.Compiled;

public sealed class DebugCompiledQuery : CompiledQuery
{


internal DebugCompiledQuery(string query, Dictionary<string, object?> variablesInternal, QueryWriter writer)
: base(query, variablesInternal)
{

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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)
Expand All @@ -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);
}
}
}
30 changes: 9 additions & 21 deletions src/EdgeDB.Net.QueryBuilder/Interfaces/IQueryBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using EdgeDB.Builders;
using EdgeDB.Compiled;
using EdgeDB.Interfaces;
using EdgeDB.Interfaces.Queries;
using EdgeDB.QueryNodes;
Expand Down Expand Up @@ -298,38 +299,25 @@ public interface IQueryBuilder
internal Dictionary<string, object?> Variables { get; }

/// <summary>
/// Builds the current query.
/// Compiles the current query.
/// </summary>
/// <remarks>
/// If the query requires introspection please use
/// <see cref="BuildAsync(IEdgeDBQueryable, CancellationToken)"/>.
/// <see cref="CompileAsync"/>.
/// </remarks>
/// <returns>
/// A <see cref="BuiltQuery"/>.
/// A <see cref="CompiledQuery"/>.
/// </returns>
BuiltQuery Build();
CompiledQuery Compile();

/// <summary>
/// Builds the current query asynchronously, allowing database introspection.
/// Compiles the current query asynchronously, allowing database introspection.
/// </summary>
/// <param name="edgedb">The client to preform introspection with.</param>
/// <param name="token">A cancellation token to cancel the asynchronous operation.</param>
/// <returns>A <see cref="BuiltQuery"/>.</returns>
ValueTask<BuiltQuery> BuildAsync(IEdgeDBQueryable edgedb, CancellationToken token = default);
/// <returns>A <see cref="CompiledQuery"/>.</returns>
ValueTask<CompiledQuery> CompileAsync(IEdgeDBQueryable edgedb, CancellationToken token = default);

/// <summary>
/// Builds the current query builder into its <see cref="BuiltQuery"/>
/// form and excludes globals from the query text and puts them in
/// <see cref="BuiltQuery.Globals"/>.
/// </summary>
/// <param name="preFinalizerModifier">
/// A modifier delegate to change nodes behaviour before the finalizer is called.
/// </param>
/// <returns>
/// A <see cref="BuiltQuery"/> which is the current query this builder has constructed.
/// </returns>
internal BuiltQuery BuildWithGlobals(Action<QueryNode>? preFinalizerModifier = null);

internal void InternalBuild(QueryWriter writer, CompileContext? context = null);
internal void CompileInternal(QueryWriter writer, CompileContext? context = null);
}
}
18 changes: 8 additions & 10 deletions src/EdgeDB.Net.QueryBuilder/Lexical/QueryWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,11 @@ public void Dispose()
}
}

public IReadOnlyDictionary<string, LinkedList<Marker>> Markers
=> _markers;
public readonly Dictionary<string, LinkedList<Marker>> Markers;

private readonly List<Marker> _markersRef;

private readonly LooseLinkedList<Value> _tokens;
private readonly Dictionary<string, LinkedList<Marker>> _markers;

private readonly List<INodeObserver> _observers = [];

Expand All @@ -43,7 +41,7 @@ public IReadOnlyDictionary<string, LinkedList<Marker>> Markers
public QueryWriter()
{
_tokens = new();
_markers = new();
Markers = new();
_markersRef = new();
_track = null;
}
Expand Down Expand Up @@ -199,12 +197,12 @@ private void UpdateMarkers(int position, int delta)
}

public bool TryGetMarker(string name, [MaybeNullWhen(false)] out LinkedList<Marker> 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);
Expand All @@ -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;

Expand Down Expand Up @@ -372,7 +370,7 @@ public StringBuilder Compile(StringBuilder? builder = null)

public void Dispose()
{
_markers.Clear();
Markers.Clear();
_tokens.Clear();
_observers.Clear();
_markersRef.Clear();
Expand Down
Loading

0 comments on commit 975f2c6

Please sign in to comment.