public void Test_Cycles() { var o = new TypeWithCycles(); o.Self = o; o.MyProperty = 5; o.Child = new Sub1 { Parent = o, SubChild = new Sub1 { Parent = o, Prop1 = 7, SubChild = new Sub1 { } } }; var c = ContentFactory.Default.CreateFrom(o); var arr = c.Visit().ToArray(); Assert.IsTrue(arr.Any(p => p.Path.Equals(ContentPath.Parse("$.Child.SubChild.SubChild")) && p.Value is ContentObject)); Assert.IsTrue(arr.Any(p => p.Path.Equals(ContentPath.Parse("$.Child.SubChild.SubChild.Prop1")) && p.Value is ContentNumber)); Assert.IsTrue(arr.Any(p => p.Path.Equals(ContentPath.Parse("$.Child.SubChild.Prop1")) && p.Value is ContentNumber)); Assert.AreEqual(10, arr.Length); }
public void Test_Expressions() { var d = new Dictionary <string, object> { { "name", "John" } }; var scope = new ContentObject(d, d, ContentFactory.Default); var e = new CreateObjectExpression(new List <CreateObjectExpression.Element> { new CreateObjectExpression.Attribute { Name = "name", Value = new PathExpression(new ScopeRootExpression(), ContentPath.Parse("$.name")) }, new CreateObjectExpression.Attribute { Name = "age", Value = new ConstantExpression(new ContentNumber(45)) } }); var issue = e.TryEvaluate(scope, out IContentNode result); Assert.IsNull(issue); var jToken = result.ToJson(); var poco = jToken.ToObject <R>(); Assert.AreEqual("John", poco.name); Assert.AreEqual(45, poco.age); }
public void Test_Parser() { var left = new AndFilter( new EqualToFilter( new PathExpression(new ScopeRootExpression(), ContentPath.Parse("$.Name")), new ConstantExpression(new ContentText("Ahmad contains"))), new ContainsFilter( new PathExpression(new ScopeRootExpression(), ContentPath.Parse("$.Friends")), new ConstantExpression(new ContentText("Sameer")))); var issues = _parser.TryParse("$.Name EQUALS \"Ahmad contains\" AND $.Friends CONTAINS \"Sameer\"", out IContentExpression actual); Assert.AreEqual(left, actual); var right = new AndFilter( new EqualToFilter( new PathExpression(new ScopeRootExpression(), ContentPath.Parse("$.Name")), new ConstantExpression(new ContentText("Suzi 34"))), new ContainsFilter( new PathExpression(new ScopeRootExpression(), ContentPath.Parse("$.Friends")), new ConstantExpression(new ContentText("Sameer")))); issues = _parser.TryParse( "($.Name EQUALS \"Ahmad contains\" AND $.Friends CONTAINS \"Sameer\")" + " OR " + "($.Name EQUALS \"Suzi 34\" AND $.Friends CONTAINS \"Sameer\")", out actual); var combined = new OrFilter(left, right); Assert.AreEqual(combined, actual); }
public void InitialTest() { //var paths = new List<Path>() //{ // new Path() // { // id = 199, // path = "$.Audit.CreatedOn", // }, // new Path() // { // id = 150, // path ="$.Name", // } // // ...etc. //}; var paths = new Dictionary <string, int> { { "$.Audit.CreatedOn", 199 }, { "$.Name", 150 }, { "$.Id", 155 }, // ...etc. }; var docType = new DocumentType(typeof(Employee)); var queryLines = new List <SearchQuery.Line>() { new SearchQuery.Line( ContentPath.Parse($"$.{nameof(Employee.Name)}") , SearchQuery.Op.Equals, ContentFactory.Default.CreateFrom("John Smith")), new SearchQuery.Line( ContentPath.Parse($"$.{nameof(Employee.Id)}") , SearchQuery.Op.Equals, ContentFactory.Default.CreateFrom(1)), }; var query = new SearchQuery(docType, queryLines, ContentPath.Parse($"$.{nameof(Employee.Id)}"), false, 0, 20); var actual = SqlResolver.ResolveSqlText(query, (s) => paths[s], "[search].[Docs]", "[search].[DocTokens]"); var expectedWithSpaces = $@"SELECT [B].* FROM (SELECT DISTINCT filtered.DocumentId, Sorted.ValueAsAny FROM ( SELECT f1.DocumentId FROM ( SELECT DocumentId FROM [search].[DocTokens] WITH (NOLOCK) WHERE ([ValueAsAny]='John Smith' AND [PathId]=150) UNION ALL SELECT DocumentId FROM [search].[DocTokens] WITH (NOLOCK) WHERE ([ValueAsAny]='011.000000' AND [PathId]=155) ) as f1 group by f1.DocumentId HAVING count(*) >= {query.QueryLines.Length} ) as filtered LEFT JOIN (SELECT DocumentId,ValueAsAny FROM [search].[DocTokens] WITH (NOLOCK) WHERE [PathId] = {paths["$.Id"]}) as Sorted ON Sorted.DocumentId = filtered.DocumentId) AS [A] INNER JOIN (SELECT * FROM [search].[Docs] WITH (NOLOCK) WHERE [SourceType] = '{query.DocumentType.Name}') AS [B] ON [A].DocumentId = [B].Id ORDER BY [A].ValueAsAny OFFSET {query.Offset} ROWS FETCH NEXT {query.Limit} ROWS ONLY"; Assert.AreEqual(Regex.Replace(expectedWithSpaces, @"\s+", string.Empty), Regex.Replace(actual, @"\s+", string.Empty)); }
private IContentPathCacheEntry ParseCacheEntry(ContentPathCacheEntryDto entry) { return(new ContentPathCacheEntryAdapter { ContentId = entry.ContentId, ContentType = LoadType(entry.ContentType), Path = ContentPath.Parse(entry.Path), HasChildren = entry.HasChildren, }); }
public void NotNull() { var paths = new Dictionary <string, int> { { "$.Audit.CreatedOn", 199 }, { "$.Name", 150 }, { "$.Id", 155 }, { "$.StartDate", 156 } // ...etc. }; var docType = new DocumentType(typeof(Employee)); var queryLines = new List <SearchQuery.Line>() { new SearchQuery.Line( ContentPath.Parse($"$.{nameof(Employee.StartDate)}") , SearchQuery.Op.NotEquals, ContentFactory.Default.CreateFrom(null)), new SearchQuery.Line( ContentPath.Parse($"$.{nameof(Employee.Name)}") , SearchQuery.Op.GreaterThanOrEquals, ContentFactory.Default.CreateFrom(new DateTime(2019, 08, 01))), new SearchQuery.Line( ContentPath.Parse($"$.{nameof(Employee.Name)}") , SearchQuery.Op.LessThanOrEquals, ContentFactory.Default.CreateFrom(new DateTime(2019, 11, 27))) }; var query = new SearchQuery(docType, queryLines, ContentPath.Parse($"$.{nameof(Employee.Id)}"), true, 0, 20); var actual = SqlResolver.ResolveSqlText(query, (s) => paths[s], "[search].[Docs]", "[search].[DocTokens]"); var expectedWithSpaces = $@"SELECT [B].* FROM (SELECT DISTINCT filtered.DocumentId, Sorted.ValueAsAny FROM ( SELECT f1.DocumentId FROM ( SELECT DocumentId FROM [search].[DocTokens] WITH (NOLOCK) WHERE ([ValueAsAny] IS NOT NULL AND [PathId]=156) UNION ALL SELECT DocumentId FROM [search].[DocTokens] WITH (NOLOCK) WHERE ([ValueAsAny]>='2019-08-01T00:00:00.0000000' AND [PathId]=150) UNION ALL SELECT DocumentId FROM [search].[DocTokens] WITH (NOLOCK) WHERE ([ValueAsAny]<='2019-11-27T00:00:00.0000000' AND [PathId]=150) ) as f1 group by f1.DocumentId HAVING count(*) >= {query.QueryLines.Length} ) as filtered LEFT JOIN (SELECT DocumentId,ValueAsAny FROM [search].[DocTokens] WITH (NOLOCK) WHERE [PathId] = {paths["$.Id"]}) as Sorted ON Sorted.DocumentId = filtered.DocumentId ) AS [A] INNER JOIN (SELECT * FROM [search].[Docs] WITH (NOLOCK) WHERE [SourceType] = '{query.DocumentType}') AS [B] ON [A].DocumentId = [B].Id ORDER BY [A].ValueAsAny DESC OFFSET {query.Offset} ROWS FETCH NEXT {query.Limit} ROWS ONLY"; Assert.AreEqual(Regex.Replace(expectedWithSpaces, @"\s+", string.Empty), Regex.Replace(actual, @"\s+", string.Empty)); }
public void GetChildrenByPath() { foreach (var root in _testContext.Roots) { foreach (var child in root.Children) { var contentInfo = _contentManager.GetContentByPath(_testContext, ContentPath.Parse(child.Alias)); Assert.Equal(child, contentInfo.Content); } } }
public void Test_Parser() { var subObject = new CreateObjectExpression(new List <CreateObjectExpression.Element> { new CreateObjectExpression.Attribute { Name = "subName", Value = new PathExpression(new ScopeRootExpression(), ContentPath.Parse("$.name")) }, new CreateObjectExpression.Attribute { Name = "subAge", Value = new ConstantExpression(new ContentNumber(45)) } }); Test("{ name: $.name, age: 45, ...{ subName: $.name, subAge: 45 } }", new CreateObjectExpression(new List <CreateObjectExpression.Element> { new CreateObjectExpression.Attribute { Name = "name", Value = new PathExpression(new ScopeRootExpression(), ContentPath.Parse("$.name")) }, new CreateObjectExpression.Attribute { Name = "age", Value = new ConstantExpression(new ContentNumber(45)) }, new CreateObjectExpression.Object { SubObject = subObject } })); Test("{}", new CreateObjectExpression(new CreateObjectExpression.Element[] { })); Test("[]", new CreateListExpression(new CreateListExpression.Element[] { })); Test("\"Yaser\"", new ConstantExpression(ContentFactory.Default.CreateFrom("Yaser"))); Test("[45]", new CreateListExpression(new CreateListExpression.Element[] { new CreateListExpression.ListItem { Value = new ConstantExpression(ContentFactory.Default.CreateFrom(45)) } })); }
public void Test_QueryHandlerAnyOf() { var list = ContentFactory.Default.CreateFrom(new[] { "123", "456" }); var a = (list as ContentList).ToArray(); Assert.IsInstanceOfType(a[0], typeof(ContentText)); Assert.IsInstanceOfType(a[1], typeof(ContentText)); var line = new SearchQuery.Line(ContentPath.Parse("$.Number.Value"), SearchQuery.Op.AnyOf, list); //var expr = QueryConversionHelper.BuildCriteriaExpr(line); }
public void AnyOf() { var paths = new Dictionary <string, int> { { "$.Audit.CreatedOn", 199 }, { "$.Name", 150 }, { "$.Id", 155 }, { "$.Phones", 156 }, // ...etc. }; var docType = new DocumentType(typeof(Employee)); var queryLines = new List <SearchQuery.Line>() { new SearchQuery.Line( ContentPath.Parse($"$.{nameof(Employee.Phones)}") , SearchQuery.Op.AnyOf, ContentFactory.Default.CreateFrom(new string[] { "0001ddd", "0002ddd", "0003ddd" })), new SearchQuery.Line( ContentPath.Parse($"$.{nameof(Employee.Name)}") , SearchQuery.Op.AnyOf, ContentFactory.Default.CreateFrom(new int[] { 1, 2, 3 })) }; var query = new SearchQuery(docType, queryLines, ContentPath.Parse($"$.{nameof(Employee.Id)}"), true, 0, 20); var actual = SqlResolver.ResolveSqlText(query, (s) => paths[s], "[search].[Docs]", "[search].[DocTokens]"); var expectedWithSpaces = $@"SELECT [B].* FROM (SELECT DISTINCT filtered.DocumentId, Sorted.ValueAsAny FROM ( SELECT f1.DocumentId FROM ( SELECT DocumentId FROM [search].[DocTokens] WITH (NOLOCK) WHERE ([ValueAsAny] IN ('0001ddd','0002ddd','0003ddd') AND [PathId]=156) UNION ALL SELECT DocumentId FROM [search].[DocTokens] WITH (NOLOCK) WHERE ([ValueAsAny] IN ('011.000000','012.000000','013.000000') AND [PathId]=150) ) as f1 group by f1.DocumentId HAVING count(*) >= {query.QueryLines.Length} ) as filtered LEFT JOIN (SELECT DocumentId,ValueAsAny FROM [search].[DocTokens] WITH (NOLOCK) WHERE [PathId] = 155) as Sorted ON Sorted.DocumentId = filtered.DocumentId ) AS [A] INNER JOIN (SELECT * FROM [search].[Docs] WITH (NOLOCK) WHERE [SourceType] = '{query.DocumentType.Name}') AS [B] ON [A].DocumentId = [B].Id ORDER BY [A].ValueAsAny DESC OFFSET {query.Offset} ROWS FETCH NEXT {query.Limit} ROWS ONLY"; Assert.AreEqual(Regex.Replace(expectedWithSpaces, @"\s+", string.Empty), Regex.Replace(actual, @"\s+", string.Empty)); }
public void Test_ContentPathParsing() { Assert.IsFalse(ContentPath.TryParse("", out ContentPath _)); Assert.IsFalse(ContentPath.TryParse(".", out _)); Assert.IsFalse(ContentPath.TryParse(".ff", out _)); Assert.IsFalse(ContentPath.TryParse("3ff.", out _)); var p1 = ContentPath.Parse("$.a.FAERF_Ar"); var p2 = ContentPath.Root.Append("a").Append("FAERF_Ar"); Assert.IsTrue(p1.Equals(p2)); Assert.IsTrue(ContentPath.Parse("$").Equals(ContentPath.Root)); Assert.IsTrue(p1.Equals(ContentPath.Parse(p1.ToString()))); Assert.IsTrue(ContentPath.Root.Equals(ContentPath.Parse(ContentPath.Root.ToString()))); }
public void Test_Evaluation() { var employee = Employee.Sample; var document = ContentFactory.Default.CreateFrom(employee); IContentNode actual = null; document.TryEvaluate(ContentPath.Parse("$.Name"), out actual); Assert.AreEqual(new ContentText(employee.Name), actual); document.TryEvaluate(ContentPath.Parse("$.Data.FavColor"), out actual); Assert.AreEqual(new ContentText("red"), actual); var result = document.TryEvaluate(ContentPath.Parse("$.Data.Start_ingSalary.Amount"), out actual); Assert.IsFalse(result); document.TryEvaluate(ContentPath.Parse("$.Data.StartingSalary.Amount"), out actual); Assert.AreEqual(new ContentNumber(500.57m), actual); // Test JSON var jsonText = JsonConvert.SerializeObject(employee); var jToken = JsonConvert.DeserializeObject <JToken>(jsonText); document = ContentFactory.Default.CreateFrom(jToken); document.TryEvaluate(ContentPath.Parse("$.Name"), out actual); Assert.AreEqual(new ContentText(employee.Name), actual); document.TryEvaluate(ContentPath.Parse("$.Data.FavColor"), out actual); Assert.AreEqual(new ContentText("red"), actual); result = document.TryEvaluate(ContentPath.Parse("$.Data.Start_ingSalary.Amount"), out actual); Assert.IsFalse(result); document.TryEvaluate(ContentPath.Parse("$.Data.StartingSalary.Amount"), out actual); Assert.AreEqual(new ContentNumber(500.57m), actual); }
public void EmptyQuery() { var paths = new Dictionary <string, int> { { "$.Audit.CreatedOn", 199 }, { "$.Id", 155 }, // ...etc. }; var docType = new DocumentType(typeof(Employee)); var queryLines = new List <SearchQuery.Line>(); var query = new SearchQuery(docType, queryLines, ContentPath.Parse($"$.{nameof(Employee.Id)}"), true, 0, 20); var actual = SqlResolver.ResolveSqlText(query, (s) => paths[s], "[search].[Docs]", "[search].[DocTokens]"); var expectedWithSpaces = $@"SELECT [B].* FROM (SELECT DISTINCT filtered.DocumentId, Sorted.ValueAsAny FROM ( SELECT f1.DocumentId FROM ( SELECT DocumentId FROM [search].[DocTokens] WITH (NOLOCK) Group by [DocumentId] ) as f1 group by f1.DocumentId HAVING count(*) >= {query.QueryLines.Length} ) as filtered LEFT JOIN (SELECT DocumentId,ValueAsAny FROM [search].[DocTokens] WITH (NOLOCK) WHERE [PathId] = {paths["$.Id"]}) as Sorted ON Sorted.DocumentId = filtered.DocumentId ) AS [A] INNER JOIN (SELECT * FROM [search].[Docs] WITH (NOLOCK) WHERE [SourceType] = '{query.DocumentType}') AS [B] ON [A].DocumentId = [B].Id ORDER BY [A].ValueAsAny DESC OFFSET 0 ROWS FETCH NEXT 20 ROWS ONLY"; Assert.AreEqual(Regex.Replace(expectedWithSpaces, @"\s+", string.Empty), Regex.Replace(actual, @"\s+", string.Empty)); }
IContentExpression ParseExpression(Queue <DslToken> q, Func <DslToken, bool> terminate) { IContentExpression exp = null; while (q.Count > 0) { var lookAhead = q.Peek(); if (terminate(lookAhead)) { break; } else if (lookAhead.IsConstant()) { if (exp != null) { throw new ParserException($"Unexpected token", lookAhead); } var token = q.DequeueAndValidate(Utils.ConstantTokens); exp = CreateConstant(token); } else if (lookAhead.TokenType == TokenType.Equals) { if (exp == null) { throw new ParserException($"Unexpected token", lookAhead); } var token = q.DequeueAndValidate(TokenType.Equals); exp = new EqualToFilter(exp, ParseExpression(q, t => t.TokenType == TokenType.And || t.TokenType == TokenType.Or || terminate(t))); } else if (lookAhead.TokenType == TokenType.Contains) { if (exp == null) { throw new ParserException($"Unexpected token", lookAhead); } var token = q.DequeueAndValidate(TokenType.Contains); exp = new ContainsFilter(exp, ParseExpression(q, t => t.TokenType == TokenType.And || t.TokenType == TokenType.Or || terminate(t))); } else if (lookAhead.TokenType == TokenType.MatchRegex) { if (exp == null) { throw new ParserException($"Unexpected token", lookAhead); } var token = q.DequeueAndValidate(TokenType.MatchRegex); var pattern = q.DequeueAndValidate(TokenType.String); exp = new RegexFilter(exp, pattern.Value); } else if (lookAhead.TokenType == TokenType.And) { if (exp == null) { throw new ParserException($"Unexpected token", lookAhead); } var token = q.DequeueAndValidate(TokenType.And); if (exp is IContentFilter leftBool) { var right = ParseExpression(q, terminate); if (right is IContentFilter rightBool) { exp = new AndFilter(leftBool, rightBool); } else { throw new ParserException("AND cannot have a right operand that does not yield boolean", token); } } else { throw new ParserException("AND cannot have a left operand that does not yield boolean", token); } } else if (lookAhead.TokenType == TokenType.Or) { if (exp == null) { throw new ParserException($"Unexpected token", lookAhead); } var token = q.DequeueAndValidate(TokenType.Or); if (exp is IContentFilter leftBool) { var right = ParseExpression(q, terminate); if (right is IContentFilter rightBool) { exp = new OrFilter(leftBool, rightBool); } else { throw new ParserException("OR cannot have a right operand that does not yield boolean", token); } } else { throw new ParserException("OR cannot have a left operand that does not yield boolean", token); } } else if (lookAhead.TokenType == TokenType.Path) { if (exp == null) { throw new ParserException($"Unexpected token", lookAhead); } var token = q.DequeueAndValidate(TokenType.Path); exp = new PathExpression(exp, ContentPath.Parse($"$.{token.Value.TrimStart('.')}")); } else if (lookAhead.TokenType == TokenType.DollarSign) { if (exp != null) { throw new ParserException($"Unexpected token", lookAhead); } q.DequeueAndValidate(TokenType.DollarSign); exp = new ScopeRootExpression(); } else if (lookAhead.TokenType == TokenType.OpenCurly) { if (exp != null) { throw new ParserException($"Unexpected token", lookAhead); } exp = CreateObjectExpression(q); } else if (lookAhead.TokenType == TokenType.OpenSquareBracket) { if (exp != null) { throw new ParserException($"Unexpected token", lookAhead); } exp = CreateListExpression(q); } else if (lookAhead.TokenType == TokenType.OpenBracket) { if (exp != null) { throw new ParserException($"Unexpected token", lookAhead); } q.DequeueAndValidate(TokenType.OpenBracket); // open bracket ( exp = ParseExpression(q, t => t.TokenType == TokenType.CloseBracket); q.DequeueAndValidate(TokenType.CloseBracket); // close bracket ) } else { throw new ParserException($"Unexpected token", lookAhead); } } if (exp == null) { throw new ParserException($"Unexpected end", null); } return(exp); }