Projections in RavenDB 4.0RC (my thoughts about them...)

448 views
Skip to first unread message

Derek den Haas

unread,
Sep 14, 2017, 9:58:34 AM9/14/17
to RavenDB - 2nd generation document database
Since you've moved from Transformers to Projections, I can't get my head around a few problems:

1. When wanting to use Projections including "LoadDocument", or now: "load", I cannot use the normal .Select() or select new (Linq) operators, from what I can find. So I have to use RawQueries.
2. RawQueries aren't bounded to my c# models, so modifications to c# models can break my RawQuery (Visual Studio won't complain about it) since it's just a string.

To put it into examples:

OLD code:
UserTransformer
- Transform = result => from a in result 
let group = LoadDocument<Group>(a.Groups) 
select new { 
    Name = a.Name, 
    Groups = group.Select(a => a.Name)
}

session.Query<UserAll.Mapping, UserAll>()
    .Where(a => a.Username == "Derek")
    .TransformWith<UserTransformer>()

NEW code:
session.Advanced.RawQuery<UserResult>("
FROM INDEX UserAll AS u
WHERE u.Username == "Derek"
LOAD u.Groups AS g
SELECT {
    Name = u.Name,
    Groups = g.map(x => x.Name)
}");

Since want to include another collection into my projection I must use a RawQuery.

My suggestion would be:
session.Query<UserAll.Mapping, UserAll>("u" // Name of collection for projection)
    .Where(a => a.Username == "Derek")
    .Load(a => a.Groups, "g" // Name of collection for projection)
    .Project("{Name = u.Name, Groups = g.map(x => x.Name)}");

Or even:
session.Query<UserAll.Mapping, UserAll>("u" // Name of collection for projection)
    .Where(a => a.Username == "Derek")
    .Load(a => a.Groups, "g" // Name of collection for projection)
    .Project<UserResult>()
        .Add(a => a.Name, "u.Name")
        .Add(a => a.Groups, "g.map(x => x.Name)");

Now I can still use Expressions for .Where(), and when using the "Or even" section, for projections and get errors when property names change.

Best of all ofcourse would be full Linq support, but I thought you were having trouble making that work?! I might be wrong about some of my statements above, since the lack of documentation at this moment, so please just ignore it when there already is a way to make this work

Derek den Haas

unread,
Sep 14, 2017, 10:23:18 AM9/14/17
to RavenDB - 2nd generation document database
What I'm feeling at the moment, in SQL Server we went from

FROM bla AS x
WHERE x.Something == "Some other thing"
SELECT x.SomethingElse, x.SomethingMore

To (EntityFramework)
var query = from a in Tables.Bla
                   where x.Something == "Some other thing"
                   select new Result() {
                       SomethingElse = SomethingElse //... etc...
}

And RavenDB went from an EntityFramework  (lambda/linq) kinda way of querying to SQL (string format), when wanting to use complex projections.
I do get that you want to make it more like SQL, though I rather have compilation errors than Query error's, and intellisense for making queries and projections.

Op donderdag 14 september 2017 15:58:34 UTC+2 schreef Derek den Haas:

Oren Eini (Ayende Rahien)

unread,
Sep 17, 2017, 4:32:09 AM9/17/17
to ravendb
This is known and there is an issue for it.

In short, we'll be working on fixing this in the very near future.

Hibernating Rhinos Ltd  

Oren Eini l CEO Mobile: + 972-52-548-6969

Office: +972-4-622-7811 l Fax: +972-153-4-622-7811

 


--
You received this message because you are subscribed to the Google Groups "RavenDB - 2nd generation document database" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Oren Eini (Ayende Rahien)

unread,
Sep 17, 2017, 4:33:44 AM9/17/17
to ravendb
The actual code we are aiming for is:

from a in session.Query<User>()
where a.Name == "Derek"
let groups = session.Load<Group>(a.Groups) 
select new { 
    Name = a.Name, 
    Groups = groups.Select(a => a.Name)
}

Oren Eini (Ayende Rahien)

unread,
Oct 9, 2017, 2:54:20 AM10/9/17
to ravendb
Hi Derek,
The code for this just landed in the 4.0 branch.
It will be available in the following nightly.
See here how it looks like:

Let me know if there is anything else that you need to do.

Hibernating Rhinos Ltd  

Oren Eini l CEO Mobile: + 972-52-548-6969

Office: +972-4-622-7811 l Fax: +972-153-4-622-7811

 


--

Derek den Haas

unread,
Oct 9, 2017, 7:13:54 AM10/9/17
to RavenDB - 2nd generation document database
That's amazing, I will take a look at it and try to make it work with the old "Transformers". I'll let you know my findings.

Op maandag 9 oktober 2017 08:54:20 UTC+2 schreef Oren Eini:
To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+u...@googlegroups.com.

Derek den Haas

unread,
Oct 11, 2017, 10:36:23 AM10/11/17
to RavenDB - 2nd generation document database
My first attempt:

            var session2 = _session.Advanced.DocumentStore.OpenSession();
            var articles = _session
                .Query<ArticleGroupAll.Mapping, ArticleGroupAll>();

            var test = from article in articles
                       where article.Name.StartsWith("Test")
                       let articleGroup = session2.Load<ArticleGroup>(article.ArticleGroupId)
                       select new
                       {
                           Name = article.Name,
                           Parent = articleGroup.Name
                       };

            var result = await test.ToListAsync();

With result:
Raven.Client.Exceptions.InvalidQueryException: 
LOAD clause is trying to use an alias but the from clause hasn't specified one: a.ArticleGroupId
Query: 
FROM INDEX 'ArticleGroupAll' 
WHERE startsWith(Name, $p0) 
LOAD a.ArticleGroupId as articleGroup 
SELECT a_Name as Name
Parameters: {"p0":"Test"}

* This is ONLY when querying from an INDEX
* session2 is used because my _session is an IAsyncDocumentSession, which has LoadAsync, which cannot be used inside a LINQ/LAMBDA expression



Second:
                var test = from article in articles
                           where article.Hide == false
                           let articleGroup = session2.Load<ArticleGroup>("articlegroups/99") // The static name is tested here
                           select new
                           {
                               Name = article.Name,
                               Parent = articleGroup.Name
                           };

                var result = await test.ToListAsync();
-- Works like a charm



Third:
              var test = from article in articles
                           where article.Hide == false
                           let articleGroup = session2.Load<ArticleGroup>(article.ArticleGroupParents).Values <-- Since it's a dictionary
                           select new
                           {
                               Name = article.Name,
                               Parent = articleGroup.First().Name
                           };
With the result:
System.NotSupportedException: 'Could not understand expression: FROM ArticleGroups.Where(article => (article.Hide == False)).Select(article => new <>f__AnonymousType0`2(article = article, articleGroup = value(Hello.Module.Controllers.HomeController+<>c__DisplayClass6_0).session2.Load(article.ArticleGroupParents).Values)).Select(<>h__TransparentIdentifier0 => new <>f__AnonymousType1`2(Name = <>h__TransparentIdentifier0.article.Name, Parent = <>h__TransparentIdentifier0.articleGroup.First().Name))'

Inner exception:
NotSupportedException: By default, Lambda2Js cannot convert custom instance methods, only static ones. `Load` is not static.



Fourth:
                var test = from article in articles
                           where article.Hide == false
                           let articleGroup = session2.Load<ArticleGroup>(article.ArticleGroupParents).Values
                           select new
                           {
                               Name = article.Name,
                               Parent = from b in article.ArticleGroupParents
                                        select new
                                        {
                                            Test = b
                                        }
                           };
-- Is working (uses .map(), no SUBQUERY if that's possible in RQL)


Fifth:
                var test = from article in articles
                           where article.Hide == false
                           let articleGroup = session2.Load<ArticleGroup>(article.ArticleGroupParents).Values
                           select new
                           {
                               Name = article.Name,
                               Parent = from b in articleGroup
                                        select new
                                        {
                                            b.Name,
                                            b.Hide
                                        }
                           };
-- See results of third

Sixth:
                var test = from article in articles
                           where article.Hide == false
                           let articleGroup = session2.Load<ArticleGroup>(article.ArticleGroupParents).Values
                               select new
                               {
                                   Name = article.Name,
                                   Parent = from b in articleGroup
                                            let articleGroup = session2.Load<ArticleGroup>("articlegroups/99")
                                            select new
                                            {
                                                b.Name,
                                                b.Hide,
                                                articleGroup.FreshDays
                                            }
                               };
-- See results of third

Those were possible using the old transformers, and would like to see them into RavenDB. When releasing RC1, I was looking at changing IQtoolkit to work with RQL (since it isn't that much different from SQL). It does a pretty good job converting LINQ to SQL, and it supports multiple "connectors".

Are those goals of RC2? Or perhaps Final?

Op maandag 9 oktober 2017 13:13:54 UTC+2 schreef Derek den Haas:

Derek den Haas

unread,
Oct 11, 2017, 10:37:30 AM10/11/17
to RavenDB - 2nd generation document database
let articleGroup = session2.Load<ArticleGroup>(article.ArticleGroupParents).Values

should be removed from the fourth test, else it will crash on something it doesn't use.

Op woensdag 11 oktober 2017 16:36:23 UTC+2 schreef Derek den Haas:

Oren Eini (Ayende Rahien)

unread,
Oct 11, 2017, 10:54:41 AM10/11/17
to ravendb
First attempt, that is a bug, see here:



session2 trick is awesome, I'm sorry, I forgot to include the proper way to show this:


                    var query = from u in asyncSession.Query<User>()
                        where u.Name != "Bob"
                        let detail = RavenQuery.Load<Detail>(u.DetailId)
                        select new
                        {
                            FullName = u.Name + " " + u.LastName,
                            Detail = detail.Number
                        };


Third & Fifth & Sixth attempts, RavenQuery.Load has an overload that accept an enumerable, so that should work.



Fourth, yes, that works as intended. We don't do subqueries, they are really complex and usually not needed in document db.



To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+unsubscribe@googlegroups.com.

Derek den Haas

unread,
Oct 12, 2017, 3:35:28 AM10/12/17
to RavenDB - 2nd generation document database
Could you maybe add RavenQuery.Metadata("....").Values<string> or something like that to make it possible to fetch metadata?

Op woensdag 11 oktober 2017 16:54:41 UTC+2 schreef Oren Eini:

Derek den Haas

unread,
Oct 12, 2017, 4:07:31 AM10/12/17
to RavenDB - 2nd generation document database
Third, new style, isn't working:
                var test = from article in articles
                           where article.Hide == false
                           let articleGroup = RavenQuery.Load<ArticleGroup>(article.ArticleGroupParents)
                           select new
                           {
                               Name = article.Name,
                               Parent = articleGroup.First().Name   <---- This one is breaking it
                           };

Exception:
'Could not understand expression: FROM ArticleGroups.Where(article => (article.Hide == False)).Select(article => new <>f__AnonymousType0`2(article = article, articleGroup = Load(article.ArticleGroupParents))).Select(<>h__TransparentIdentifier0 => new <>f__AnonymousType1`2(Name = <>h__TransparentIdentifier0.article.Name, Parent = <>h__TransparentIdentifier0.articleGroup.First().Name))'
Inner exception:
ArgumentException: Not supported computation: <>h__TransparentIdentifier0.articleGroup.First().Name. You cannot use computation in RavenDB queries (only simple member expressions are allowed).

Fifth (or so):

                var test = from article in articles
                           where article.Hide == false
                           let articleGroup = RavenQuery.Load<ArticleGroup>(article.ArticleGroupParents)
                           select new
                           {
                               Name = article.Name,
                               Parent = from b in articleGroup
                                        select new
                                        {
                                            b.Name,
                                            b.Hide
                                        }
                           };

Exception:
Raven.Client.Exceptions.InvalidQueryException: 'Raven.Client.Exceptions.InvalidQueryException: Select clause contains invalid script
Query: FROM ArticleGroups as article WHERE Hide = $p0 LOAD article.ArticleGroupParents as articleGroup[] SELECT { Name : article.Name, Parent : <>h__TransparentIdentifier0.articleGroup.map(function(b){return {Name:b.Name,Hide:b.Hide};}) } ---> Esprima.ParserException: Line 1': Unexpected token <
   at Esprima.JavaScriptParser.ThrowUnexpectedToken(Token token, String message)
   at Esprima.JavaScriptParser.ParsePrimaryExpression()
   at Esprima.JavaScriptParser.InheritCoverGrammar[T](Func`1 parseFunction)
   at Esprima.JavaScriptParser.ParseLeftHandSideExpressionAllowCall()
   at Esprima.JavaScriptParser.InheritCoverGrammar[T](Func`1 parseFunction)
   at Esprima.JavaScriptParser.ParseUpdateExpression()
   at Esprima.JavaScriptParser.ParseUnaryExpression()
   at Esprima.JavaScriptParser.InheritCoverGrammar[T](Func`1 parseFunction)
   at Esprima.JavaScriptParser.ParseExponentiationExpression()
   at Esprima.JavaScriptParser.InheritCoverGrammar[T](Func`1 parseFunction)
   at Esprima.JavaScriptParser.ParseBinaryExpression()
   at Esprima.JavaScriptParser.InheritCoverGrammar[T](Func`1 parseFunction)
   at Esprima.JavaScriptParser.ParseConditionalExpression()
   at Esprima.JavaScriptParser.ParseAssignmentExpression()
   at Esprima.JavaScriptParser.InheritCoverGrammar[T](Func`1 parseFunction)
   at Esprima.JavaScriptParser.ParseObjectProperty(Token hasProto)
   at Esprima.JavaScriptParser.ParseObjectInitializer()
   at Esprima.JavaScriptParser.InheritCoverGrammar[T](Func`1 parseFunction)
   at Esprima.JavaScriptParser.ParsePrimaryExpression()
   at Esprima.JavaScriptParser.InheritCoverGrammar[T](Func`1 parseFunction)
   at Esprima.JavaScriptParser.ParseLeftHandSideExpressionAllowCall()
   at Esprima.JavaScriptParser.InheritCoverGrammar[T](Func`1 parseFunction)
   at Esprima.JavaScriptParser.ParseUpdateExpression()
   at Esprima.JavaScriptParser.ParseUnaryExpression()
   at Esprima.JavaScriptParser.InheritCoverGrammar[T](Func`1 parseFunction)
   at Esprima.JavaScriptParser.ParseExponentiationExpression()
   at Esprima.JavaScriptParser.InheritCoverGrammar[T](Func`1 parseFunction)
   at Esprima.JavaScriptParser.ParseBinaryExpression()
   at Esprima.JavaScriptParser.InheritCoverGrammar[T](Func`1 parseFunction)
   at Esprima.JavaScriptParser.ParseConditionalExpression()
   at Esprima.JavaScriptParser.ParseAssignmentExpression()
   at Esprima.JavaScriptParser.IsolateCoverGrammar[T](Func`1 parseFunction)
   at Esprima.JavaScriptParser.ParseExpression()
   at Esprima.JavaScriptParser.ParseReturnStatement()
   at Esprima.JavaScriptParser.ParseStatement()
   at Esprima.JavaScriptParser.ParseStatementListItem()
   at Esprima.JavaScriptParser.ParseProgram(Boolean strict)
   at Raven.Server.Documents.Queries.Parser.QueryParser.SelectClause(String clause, Query query) in C:\Builds\RavenDB-4.0-Nightly\src\Raven.Server\Documents\Queries\Parser\QueryParser.cs:line 266
   --- End of inner exception stack trace ---
   at Raven.Server.Documents.Queries.Parser.QueryParser.SelectClause(String clause, Query query) in C:\Builds\RavenDB-4.0-Nightly\src\Raven.Server\Documents\Queries\Parser\QueryParser.cs:line 270
   at Raven.Server.Documents.Queries.Parser.QueryParser.Parse(QueryType queryType) in C:\Builds\RavenDB-4.0-Nightly\src\Raven.Server\Documents\Queries\Parser\QueryParser.cs:line 67
   at Raven.Server.Documents.Queries.QueryMetadata..ctor(String query, BlittableJsonReaderObject parameters, UInt64 cacheKey, QueryType queryType) in C:\Builds\RavenDB-4.0-Nightly\src\Raven.Server\Documents\Queries\QueryMetadata.cs:line 31
   at Raven.Server.Documents.Queries.IndexQueryServerSide.Create(BlittableJsonReaderObject json, JsonOperationContext context, QueryMetadataCache cache, QueryType queryType) in C:\Builds\RavenDB-4.0-Nightly\src\Raven.Server\Documents\Queries\IndexQueryServerSide.cs:line 54
   at Raven.Server.Documents.Handlers.QueriesHandler.<GetIndexQuery>d__4.MoveNext() in C:\Builds\RavenDB-4.0-Nightly\src\Raven.Server\Documents\Handlers\QueriesHandler.cs:line 172
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Raven.Server.Documents.Handlers.QueriesHandler.<Query>d__3.MoveNext() in C:\Builds\RavenDB-4.0-Nightly\src\Raven.Server\Documents\Handlers\QueriesHandler.cs:line 133
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Raven.Server.Documents.Handlers.QueriesHandler.<Post>d__0.MoveNext() in C:\Builds\RavenDB-4.0-Nightly\src\Raven.Server\Documents\Handlers\QueriesHandler.cs:line 65
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Raven.Server.Routing.RequestRouter.<HandlePath>d__5.MoveNext() in C:\Builds\RavenDB-4.0-Nightly\src\Raven.Server\Routing\RequestRouter.cs:line 107
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at System.Runtime.CompilerServices.ValueTaskAwaiter`1.GetResult()
   at Raven.Server.RavenServerStartup.<RequestHandler>d__11.MoveNext() in C:\Builds\RavenDB-4.0-Nightly\src\Raven.Server\RavenServerStartup.cs:line 157'

And therefore the sixth attempt is also failing, (unable to test at this moment).



Op donderdag 12 oktober 2017 09:35:28 UTC+2 schreef Derek den Haas:

Oren Eini (Ayende Rahien)

unread,
Oct 12, 2017, 10:08:48 AM10/12/17
to ravendb
To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+unsubscribe@googlegroups.com.

Oren Eini (Ayende Rahien)

unread,
Oct 12, 2017, 10:09:26 AM10/12/17
to ravendb
What is "articles" in this context?
To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+unsubscribe@googlegroups.com.

Derek den Haas

unread,
Oct 12, 2017, 10:30:08 AM10/12/17
to RavenDB - 2nd generation document database
            var articles = _session
                .Query<ArticleGroupAll.Mapping, ArticleGroupAll>();

it's actually ArticleGroups:

class ArticleGroup {
    string Id
    List<string> ArticleGroupParents
    string Name
    bool Hide
}

That's all I'm using for these tests. But to make it more like your example on an earlier blog post:

class User {
    string Id
    string Name
    string Url
    DateTime LastActive
}
class Post {
    class Comment {
        string UserId
        string Message
    }
    
    string Title
    string Message
    List<Comment> Comments
}

Now I want to do this:

var posts = session.Query<Post>();
from post in posts
select new {
    Title = post.Title
    Message = post.Message
    Comments = from comment in post.Comments
               let user = RavenQuery.Load(comment.UserId)
               select new {
                   User = user.Name
                   Message = comment.Message
               }
}



Op donderdag 12 oktober 2017 16:09:26 UTC+2 schreef Oren Eini:

Oren Eini (Ayende Rahien)

unread,
Oct 12, 2017, 10:32:46 AM10/12/17
to ravendb
To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+unsubscribe@googlegroups.com.

Derek den Haas

unread,
Oct 12, 2017, 10:44:51 AM10/12/17
to RavenDB - 2nd generation document database
Maybe you also want to add this one:
            var articleGroups = _session.Query<ArticleGroupAll.Mapping, ArticleGroupAll>();
                var test = from articleGroup in articleGroups 
                           where article.Hide == false
                           let parentGroups = RavenQuery.Load<ArticleGroup>(article.ArticleGroupParents)
                           select new
                           {
                               Name = articleGroup.Name,
                               Parent = parentGroups.First().Name   <---- This one is breaking it
                           };

Exception:
'Could not understand expression: FROM ArticleGroups.Where(article => (articleGroup.Hide == False)).Select(articleGroup => new <>f__AnonymousType0`2(articleGroup = articleGroup, parentGroup = Load(article.ArticleGroupParents))).Select(<>h__TransparentIdentifier0 => new <>f__AnonymousType1`2(Name = <>h__TransparentIdentifier0.articleGroup.Name, Parent = <>h__TransparentIdentifier0.parentGroup.First().Name))'
Inner exception:
ArgumentException: Not supported computation: <>h__TransparentIdentifier0.articleGroup.First().Name. You cannot use computation in RavenDB queries (only simple member expressions are allowed).
Inner exception:
ArgumentException: Not supported computation: <>h__TransparentIdentifier0.articleGroup.First().Name. You cannot use computation in RavenDB queries (only simple member expressions are allowed).


Op donderdag 12 oktober 2017 16:32:46 UTC+2 schreef Oren Eini:

Oren Eini (Ayende Rahien)

unread,
Oct 12, 2017, 10:46:50 AM10/12/17
to ravendb
Updated
To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+unsubscribe@googlegroups.com.

Derek den Haas

unread,
Oct 12, 2017, 11:36:50 AM10/12/17
to RavenDB - 2nd generation document database
Got another one:

        public enum CommentState
        {
            Start = 0,
            Dismissed = 1,
            Confirmed = 2
        }
        public class Comment
        {
            public string Username { get; set; }
            public string Message { get; set; }
            public CommentState CommentState { get; set; }
        }

        [TestMethod]
        public async Task CanProjectNullCoalescingOperator()
        {
            using (var store = GetDocumentStore())
            {
                using (var session = store.OpenSession())
                {
                    for(var x = 0; x < 10; x++)
                    {
                        session.Store(new Comment()
                        {
                            Username = x%5 == 0 ? null : "User " + x,
                            Message = "Just a little message",
                            CommentState = (CommentState)(x % 3)
                        });
                    }
                    session.SaveChanges();
                }

                using (var session = store.OpenAsyncSession())
                {
                    var comments = session.Query<Comment>();

                    var test = from a in comments
                               select new
                               {
                                   Username = a.Username ?? "Has no username",
                                   Message = a.Message
                               };

                    var result = await test.ToListAsync();

                    Assert.AreEqual(10, result.Count);
                }
            }
        }

Results into:
'Raven.Client.Exceptions.InvalidQueryException: Select clause contains invalid script
Query: FROM Comments as a SELECT { Username : a.Username"Has no username", Message : a.Message }

Op donderdag 12 oktober 2017 16:46:50 UTC+2 schreef Oren Eini:

Oren Eini (Ayende Rahien)

unread,
Oct 12, 2017, 11:46:23 AM10/12/17
to ravendb
http://issues.hibernatingrhinos.com/issue/RavenDB-8965

BTW, feel free to open the issues directly.
To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+unsubscribe@googlegroups.com.

Derek den Haas

unread,
Oct 12, 2017, 12:21:25 PM10/12/17
to RavenDB - 2nd generation document database
Do you want one per type of issue (found some error's in nested "if" statements using conditional operator), or as much as possible in one?

Op donderdag 12 oktober 2017 17:46:23 UTC+2 schreef Oren Eini:

Oren Eini (Ayende Rahien)

unread,
Oct 12, 2017, 12:22:59 PM10/12/17
to ravendb
One per issue would be great
To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+unsubscribe@googlegroups.com.

Derek den Haas

unread,
Oct 12, 2017, 1:33:54 PM10/12/17
to RavenDB - 2nd generation document database
Ok created a few, but I don't know how complex you want to go with Linq to RQL, since it's missing for example:
                    var test = from post in session.Query<Post>()
                               select new
                               {
                                   DateTime = post.DateTime.ToString("dd-MM-yyyy"),
                                   DateTimeUtc = post.DateTime.ToUniversalTime()
                               };

Which I didn't report, I think basic support should (like SQL does) support:
Math functions (created issue 8968) (max / min / count / pow / abs etc.)
String functions (created issue 8967) (join / substring / padleft / padright etc.)
Date functions (no issue created) (format / addDay / Month / Year / Utc? / .Date?)
-- There are some! Implemented if I remember correct from your GIT

Op donderdag 12 oktober 2017 18:22:59 UTC+2 schreef Oren Eini:

Oren Eini (Ayende Rahien)

unread,
Oct 12, 2017, 1:48:24 PM10/12/17
to ravendb
At some point we are going to cry uncle, yes. And I don't have a firm line to say yay or nay for things, but keep them coming, and as long as they are reasonable, we'll try to make it work. A lot of that depends on the complexity on implementation.

DateTime in particular is _hard_ in JS, and there isn't really a good point in doing date conversions on the server side vs. client side.
To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+unsubscribe@googlegroups.com.

Derek den Haas

unread,
Oct 12, 2017, 2:07:55 PM10/12/17
to RavenDB - 2nd generation document database
Yep, therefore I left it out of your bug tracker.

String, 
Math (ceil / round / floor / abs / min / max / pow), 
true ? false : true (and nested), 
null ?? "Something else"
Load (list or single item)
SubSelects
SubSelects with Load
Basic calculations (+ - * / & ^ |)

And maybe (have to test them):
- List functions: Max / Min / Count / Sum / .First() / .Last()
- Array/Dictionary access (item.Description["english"] or item.Description["german"] or [0])
- Group by
- Multi group by

And finally:
- ToList()
- ToDictionary()

Should give me a really good base. In my case, about 97.532% of my original transformers can be converted when having those features.

Op donderdag 12 oktober 2017 19:48:24 UTC+2 schreef Oren Eini:

Oren Eini (Ayende Rahien)

unread,
Oct 12, 2017, 2:10:03 PM10/12/17
to ravendb
Please note that even if we won't support them, we still want to be able to recognize it and error properly.
To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+unsubscribe@googlegroups.com.

Marko Lahma

unread,
Oct 13, 2017, 4:49:58 AM10/13/17
to RavenDB - 2nd generation document database

There still are IRavenQueryable.AddTransformerParameter and IRavenQueryProvider.AddTransformerParameter, should they exist anymore?

Derek den Haas

unread,
Oct 13, 2017, 5:29:48 AM10/13/17
to RavenDB - 2nd generation document database
Just another thought when not supporting some of those functions, why don't you add:

RavenQuery.Raw<ExpectedReturnType>("article.Member.toUTC()");

For example:

from article in session.Query<Article>()
select new {
    Date = RavenQuery.Raw<DateTime>("article.DateTime.toUTC()");
    Name = RavenQuery.Raw<string>("article.Name.substr(0,3).padStart(0,5)")
}

or to keep it stronger typed:

from article in session.Query<Article>()
select new {
    Date = RavenQuery.Raw<DateTime>(a => a.DateTime, "toUTC()");
    Name = RavenQuery.Raw<string>(a => a.Name, "substr(0,3).padStart(0,5)")
}

Just a thought.

Op donderdag 12 oktober 2017 20:10:03 UTC+2 schreef Oren Eini:

Oren Eini (Ayende Rahien)

unread,
Oct 15, 2017, 5:30:08 AM10/15/17
to ravendb
No, we'll be removing them.
To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+unsubscribe@googlegroups.com.

Oren Eini (Ayende Rahien)

unread,
Oct 15, 2017, 5:30:32 AM10/15/17
to ravendb
Derek, Yes, I like this.
To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+unsubscribe@googlegroups.com.

Derek den Haas

unread,
Oct 20, 2017, 11:37:42 AM10/20/17
to RavenDB - 2nd generation document database
About the RavenQuery.Raw<string>()

when doing:
var query = from article in session.Query<Article>()
                   select new {
                        Name = RavenQuery.Raw<string>("article.Name.padLeft(???)")
                   }
It does make sense that the name should be "article", though when doing:

var test = new session.Query<artlicle>()
test.Where(a => a.Name == "Test").Select(a => new {
    Name = RavenQuery.Raw<string>(".... ehm I don't know :)")
});

It's a bit harder to know what the variable name is that's being used. Isn't it possible to also implement:
var test = new session.Query<artlicle>()
test.Where(a => a.Name == "Test").Select(a => new {
    Name = RavenQuery.Raw<string>(a.Name, "padLeft(???)")
});
It also makes it a bit more typed.

Op zondag 15 oktober 2017 11:30:32 UTC+2 schreef Oren Eini:

Oren Eini (Ayende Rahien)

unread,
Oct 22, 2017, 1:34:40 AM10/22/17
to ravendb

Derek den Haas

unread,
Oct 27, 2017, 10:03:52 AM10/27/17
to RavenDB - 2nd generation document database
Can I make a PR to add some support for String? These are all the functions found in String:

IndexOf, 
Contains -> Javascript: IndexOf !== -1, 
StartsWith, 
EndsWith, 
Split

Maybe trim support:
Trim, 
TrimEnd, 
TrimStart,

Though I know on the serverside you are some polyfills to get things done.

Also missing some IEnumerable/List functions that might be usefull, or do you want an issue to implement them yourself?

Op zondag 22 oktober 2017 07:34:40 UTC+2 schreef Oren Eini:

Oren Eini (Ayende Rahien)

unread,
Oct 29, 2017, 4:18:28 AM10/29/17
to ravendb
A PR would be wonderful, yes.
--

Derek den Haas

unread,
Oct 30, 2017, 6:59:53 AM10/30/17
to RavenDB - 2nd generation document database
What version of ECMAScript are you trying to support?

Reason for this question, .Contains could be converted to .includes (ES6). I could use a polyfill, though I don't know where your support will end of JS:

Oren Eini (Ayende Rahien)

unread,
Oct 30, 2017, 7:02:42 AM10/30/17
to ravendb
We support ECMA2015 + arrow functions. 
Basically whatever Jint does
--

Derek den Haas

unread,
Oct 30, 2017, 9:52:33 AM10/30/17
to RavenDB - 2nd generation document database
Ok, .includes doesn't exist in Jint, though is included in ES6/ES2015. Polyfill or translate contains differently (can use indexOf() !== -1), though includes == contains

Op maandag 30 oktober 2017 12:02:42 UTC+1 schreef Oren Eini:

Oren Eini (Ayende Rahien)

unread,
Oct 30, 2017, 10:01:17 AM10/30/17
to ravendb
Index of is better

--

Derek den Haas

unread,
Oct 31, 2017, 5:03:06 PM10/31/17
to RavenDB - 2nd generation document database
Finally had some spare time, created a pull request, tried to follow your coding guidelines, please let me know. If you like it I might extend some other parts.

Had more troubles with your "commit/message/conventions" which are behind password, than the actual code :/

Op maandag 30 oktober 2017 15:01:17 UTC+1 schreef Oren Eini:

Oren Eini (Ayende Rahien)

unread,
Nov 1, 2017, 3:22:47 PM11/1/17
to ravendb
What was the trouble? 

And thanks, I've merged both your PRs
--

Derek den Haas

unread,
Nov 2, 2017, 6:47:46 AM11/2/17
to RavenDB - 2nd generation document database
It wasn't containing a valid issue number (you can only see that by hovering over it, since it breaks the text, and the Details button is pointing to an environment I cannot login). If you want next time I can first create an issue before adding the PR. Though there isn't anything left on my list to add :)

Op woensdag 1 november 2017 20:22:47 UTC+1 schreef Oren Eini:
Index of is better

Updated
<font face="co
Reply all
Reply to author
Forward
0 new messages