Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial serialization for query fragments #25

Merged
merged 11 commits into from
Dec 13, 2023
116 changes: 116 additions & 0 deletions Fauna.Test/QueryExpr.Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
using NUnit.Framework;
using System.Text.RegularExpressions;
using static Fauna.Query;

namespace Fauna.Test;

[TestFixture]
public class QueryExprTests
{
[Test]
public void Ctor_WithList()
{
var fragment1 = new QueryLiteral("fragment1");
var fragment2 = new QueryExpr(new QueryLiteral("fragment2"));
var fragment3 = new QueryVal<int>(123);
var expected = new List<IQueryFragment> { fragment1, fragment2, fragment3 };

var actual1 = new QueryExpr(expected);
var actual2 = new QueryExpr(fragment1, fragment2, fragment3);

Assert.AreEqual(expected.AsReadOnly(), actual1.Fragments);
Assert.AreEqual(expected.AsReadOnly(), actual2.Fragments);
}

[Test]
public void Ctor_WithValidFragments_ShouldNotThrowException()
{
var validFragments = new IQueryFragment[]
{
new QueryLiteral("fragment1"),
new QueryExpr(new QueryLiteral("fragment2")),
new QueryVal<int>(123)
};

Assert.DoesNotThrow(() => new QueryExpr(validFragments));
}

[Test]
public void ToString_ReturnsExpectedValue()
{
var expr = new QueryExpr(new QueryLiteral("item1"), new QueryLiteral("item2"));
var expectedString = "QueryExpr(QueryLiteral(item1),QueryLiteral(item2))";
Assert.AreEqual(expectedString, expr.ToString());
}

[Test]
public void GetHashCode_ReturnsConsistentValue()
{
var expr = new QueryExpr(new QueryLiteral("item1"));
int hashCode1 = expr.GetHashCode();
int hashCode2 = expr.GetHashCode();
Assert.AreEqual(hashCode1, hashCode2);
}

[Test]
public void Equality_WithSameValue()
{
var expr1 = new QueryExpr(new QueryLiteral("item1"), new QueryLiteral("item2"));
var expr2 = new QueryExpr(new QueryLiteral("item1"), new QueryLiteral("item2"));
Assert.IsTrue(expr1.Equals(expr2));
}

[Test]
public void Inequality_WithDifferentValue()
{
var expr1 = new QueryExpr(new QueryLiteral("item1"), new QueryLiteral("item2"));
var expr2 = new QueryExpr(new QueryLiteral("item3"), new QueryLiteral("item4"));
Assert.IsFalse(expr1.Equals(expr2));
}

[Test]
public void EqualityOperator_WithSameValue()
{
var expr1 = new QueryExpr(new QueryLiteral("item1"), new QueryLiteral("item2"));
var expr2 = new QueryExpr(new QueryLiteral("item1"), new QueryLiteral("item2"));
Assert.IsTrue(expr1 == expr2);
}

[Test]
public void InequalityOperator_WithDifferentValue()
{
var expr1 = new QueryExpr(new QueryLiteral("item1"), new QueryLiteral("item2"));
var expr2 = new QueryExpr(new QueryLiteral("item3"), new QueryLiteral("item4"));
Assert.IsTrue(expr1 != expr2);
}

[Test]
public void Serialize_WithSubquery()
{
int backorderLimit = 15;
bool isBackordered = false;
var subQuery = FQL($@"let product = Product.firstWhere(.backorderLimit == {backorderLimit} && .backordered == {isBackordered})!; product.quantity;");
var mainQuery = FQL($@"Product.where(.quantity == {subQuery}).order(.title) {{ name, description }}");
string formattedExpected = @"
{
""fql"": [
""Product.where(.quantity == "",
{
""fql"": [
""let product = Product.firstWhere(.backorderLimit == "",
{ ""value"": { ""@int"": ""15""} },
"" && .backordered == "",
{ ""value"": false },
"")!; product.quantity;""
]
},
"").order(.title) { name, description }""
]
}";
string expected = Regex.Replace(formattedExpected, "(\"(?:[^\"\\\\]|\\\\.)*\")|\\s+", "$1");

var actual = mainQuery.Serialize();

Assert.AreEqual(expected, actual);
}
}
80 changes: 80 additions & 0 deletions Fauna.Test/QueryLiteral.Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using NUnit.Framework;

namespace Fauna.Test;

[TestFixture]
public class QueryLiteralTests
{
[Test]
public void Ctor_WithValidValue()
{
string expected = "test value";
var queryLiteral = new QueryLiteral(expected);
Assert.AreEqual(expected, queryLiteral.Unwrap);
}

[Test]
public void Ctor_WithNullValue_ThrowsArgumentNullException()
{
string? literal = null;
Assert.Throws<ArgumentNullException>(() => new QueryLiteral(literal));

Check warning on line 20 in Fauna.Test/QueryLiteral.Tests.cs

View workflow job for this annotation

GitHub Actions / dotnet-test (8.0.x)

Possible null reference argument for parameter 'v' in 'QueryLiteral.QueryLiteral(string v)'.
}

[Test]
public void ToString_ReturnsExpectedValue()
{
var queryLiteral = new QueryLiteral("test value");
var expectedString = "QueryLiteral(test value)";
Assert.AreEqual(expectedString, queryLiteral.ToString());
}

[Test]
public void Equals_WithSameValue()
{
var literal1 = new QueryLiteral("test");
var literal2 = new QueryLiteral("test");
Assert.IsTrue(literal1.Equals(literal2));
}

[Test]
public void Equals_WithDifferentValue()
{
var literal1 = new QueryLiteral("test1");
var literal2 = new QueryLiteral("test2");
Assert.IsFalse(literal1.Equals(literal2));
}

[Test]
public void EqualityOperator_WithSameValue()
{
var literal1 = new QueryLiteral("test");
var literal2 = new QueryLiteral("test");
Assert.IsTrue(literal1 == literal2);
}

[Test]
public void InequalityOperator_WithDifferentValue()
{
var literal1 = new QueryLiteral("test1");
var literal2 = new QueryLiteral("test2");
Assert.IsTrue(literal1 != literal2);
}

[Test]
public void GetHashCode_ReturnsConsistentValue()
{
var literal = new QueryLiteral("test");
int hashCode1 = literal.GetHashCode();
int hashCode2 = literal.GetHashCode();
Assert.AreEqual(hashCode1, hashCode2);
}

[Test]
public void Serialize_ReturnsCorrectStringValue()
{
var queryLiteral = new QueryLiteral("test value");
var expected = "\"test value\"";
var actual = queryLiteral.Serialize();
Assert.AreEqual(expected, actual);
}
}
20 changes: 20 additions & 0 deletions Fauna.Test/QueryVal.Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,24 @@ public void InequalityOperator_WithDifferentValue()

Assert.IsTrue(val1 != val2);
}

[Test]
public void Serialize_WithIntValue()
{
int intValue = 5;
string intExpected = $@"{{""value"":{{""@int"":""{intValue}""}}}}";
var intActual = new QueryVal<int>(intValue).Serialize();

Assert.AreEqual(intExpected, intActual);
}

[Test]
public void Serialize_WithBoolValue()
{
bool boolValue = true;
string boolExpected = $@"{{""value"":{boolValue.ToString().ToLowerInvariant()}}}";
var boolActual = new QueryVal<bool>(boolValue).Serialize();

Assert.AreEqual(boolExpected, boolActual);
}
}
6 changes: 6 additions & 0 deletions Fauna/Query/IQueryFragment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,10 @@
/// </summary>
public interface IQueryFragment
{
/// <summary>
/// Serializes the query fragment into a string format.
/// </summary>
/// <returns>A string representation of the query fragment.</returns>
void Serialize(Stream stream);
string Serialize();
}
18 changes: 17 additions & 1 deletion Fauna/Query/Query.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
using System.Text;

namespace Fauna;

public abstract class Query : IEquatable<Query>
public abstract class Query : IEquatable<Query>, IQueryFragment
{
public void Serialize(Stream stream)
{
SerializeInternal(stream);
}

public string Serialize()
{
using var ms = new MemoryStream();
SerializeInternal(ms);
return Encoding.UTF8.GetString(ms.ToArray());
}

protected abstract void SerializeInternal(Stream stream);

public abstract override int GetHashCode();

public abstract override bool Equals(object? otherObject);
Expand Down
5 changes: 5 additions & 0 deletions Fauna/Query/QueryArr.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ public QueryArr(IEnumerable<T> v)

public T this[int index] => Unwrap[index];

protected override void SerializeInternal(Stream stream)
{
throw new NotImplementedException();
}

public override bool Equals(Query? o)
{
return o is QueryArr<T> other && Unwrap.SequenceEqual(other.Unwrap);
Expand Down
20 changes: 20 additions & 0 deletions Fauna/Query/QueryExpr.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using System.Collections.ObjectModel;
using System.Text;
using System.Text.Json;
using Fauna.Serialization;

namespace Fauna;

Expand All @@ -18,6 +21,23 @@ public QueryExpr(params IQueryFragment[] fragments)

public ReadOnlyCollection<IQueryFragment> Fragments => Unwrap;

protected override void SerializeInternal(Stream stream)
{
stream.Write(Encoding.UTF8.GetBytes("{\"fql\":["));
for (var i = 0; i < Unwrap.Count; i++)
{
var t = Unwrap[i];
t.Serialize(stream);
if (i < Unwrap.Count - 1)
{
stream.Write(Encoding.UTF8.GetBytes(","));
}
}

stream.Write(Encoding.UTF8.GetBytes("]}"));
stream.Flush();
}

public override bool Equals(Query? o) => IsEqual(o as QueryExpr);

public override bool Equals(object? o)
Expand Down
11 changes: 10 additions & 1 deletion Fauna/Query/QueryLiteral.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
namespace Fauna;
using System.Text;
using System.Text.Json;

namespace Fauna;

public sealed class QueryLiteral : Query, IQueryFragment
{
Expand All @@ -19,6 +22,12 @@ public override string ToString()
return $"QueryLiteral({Unwrap})";
}

protected override void SerializeInternal(Stream stream)
{
stream.Write(Encoding.UTF8.GetBytes($"\"{Unwrap}\""));
stream.Flush();
}

public override bool Equals(Query? otherQuery)
{
if (otherQuery is null)
Expand Down
14 changes: 13 additions & 1 deletion Fauna/Query/QueryVal.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
namespace Fauna;
using System.Text;
using System.Text.Json;
using Fauna.Serialization;

namespace Fauna;

public sealed class QueryVal<T> : Query, IQueryFragment
{
Expand All @@ -9,6 +13,14 @@ public QueryVal(T v)

public T Unwrap { get; }

protected override void SerializeInternal(Stream stream)
{
stream.Write(Encoding.UTF8.GetBytes("{\"value\":"));
Serializer.Serialize(stream, Unwrap);
stream.Write(Encoding.UTF8.GetBytes("}"));
stream.Flush();
}

public override bool Equals(Query? o) => IsEqual(o as QueryVal<T>);

public override bool Equals(object? o)
Expand Down
Loading