6
6
using System . Reflection ;
7
7
using Baseline ;
8
8
using Marten . Linq . Fields ;
9
+ using Marten . Linq . SqlProjection ;
9
10
using Remotion . Linq . Parsing ;
11
+ using Weasel . Postgresql . SqlGeneration ;
10
12
11
13
namespace Marten . Linq . Parsing
12
14
{
13
15
internal class SelectTransformBuilder : RelinqExpressionVisitor
14
16
{
15
17
private TargetObject _target ;
16
- private SelectedField _currentField ;
18
+ private BindingTarget _currentTarget ;
17
19
18
20
public SelectTransformBuilder ( Expression clause , IFieldMapping fields , ISerializer serializer )
19
21
{
@@ -35,7 +37,7 @@ protected override Expression VisitNew(NewExpression expression)
35
37
36
38
for ( var i = 0 ; i < parameters . Length ; i ++ )
37
39
{
38
- _currentField = _target . StartBinding ( parameters [ i ] . Name ) ;
40
+ _currentTarget = _target . StartBinding ( parameters [ i ] . Name ) ;
39
41
Visit ( expression . Arguments [ i ] ) ;
40
42
}
41
43
@@ -44,21 +46,76 @@ protected override Expression VisitNew(NewExpression expression)
44
46
45
47
protected override Expression VisitMember ( MemberExpression node )
46
48
{
47
- _currentField . Add ( node . Member ) ;
49
+ _currentTarget . AddMember ( node . Member ) ;
48
50
return base . VisitMember ( node ) ;
49
51
}
50
52
51
53
protected override MemberBinding VisitMemberBinding ( MemberBinding node )
52
54
{
53
- _currentField = _target . StartBinding ( node . Member . Name ) ;
55
+ _currentTarget = _target . StartBinding ( node . Member . Name ) ;
54
56
55
57
return base . VisitMemberBinding ( node ) ;
56
58
}
57
59
60
+ protected override Expression VisitMethodCall ( MethodCallExpression node )
61
+ {
62
+ var fragment = SqlProjectionSqlFragment . TryParse ( node ) ;
63
+ if ( fragment == null )
64
+ {
65
+ throw new NotSupportedException (
66
+ $ "Method { node . Method . DeclaringType ? . FullName } .{ node . Method . Name } is not supported.") ;
67
+ }
68
+
69
+ _currentTarget . AddSqlProjection ( fragment ) ;
70
+
71
+ return base . VisitMethodCall ( node ) ;
72
+ }
73
+
74
+ public class BindingTarget : TargetObject . ISetterBinding
75
+ {
76
+ private readonly string _name ;
77
+ private TargetObject . SetterBinding _field ;
78
+ private TargetObject . SqlProjectionBinding _sqlProjection ;
79
+
80
+ public BindingTarget ( string name )
81
+ {
82
+ _name = name ;
83
+ }
84
+
85
+ public void AddMember ( MemberInfo memberInfo )
86
+ {
87
+ if ( _sqlProjection != null )
88
+ {
89
+ throw new InvalidOperationException (
90
+ "Cannot bind to a member after having bound to a sql projection" ) ;
91
+ }
92
+
93
+ _field ??= new TargetObject . SetterBinding ( _name ) ;
94
+ _field . Field . Add ( memberInfo ) ;
95
+ }
96
+
97
+ public void AddSqlProjection ( ISqlFragment sqlProjectionClause )
98
+ {
99
+ if ( _field != null )
100
+ {
101
+ throw new InvalidOperationException (
102
+ "Cannot bind to a sql projection after having bound to a member." ) ;
103
+ }
104
+
105
+ _sqlProjection = new TargetObject . SqlProjectionBinding ( _name , sqlProjectionClause ) ;
106
+ }
107
+
108
+ public string ToJsonBuildObjectPair ( IFieldMapping mapping , ISerializer serializer )
109
+ {
110
+ return _field ? . ToJsonBuildObjectPair ( mapping , serializer )
111
+ ?? _sqlProjection ? . ToJsonBuildObjectPair ( mapping , serializer )
112
+ ?? string . Empty ;
113
+ }
114
+ }
58
115
59
116
public class TargetObject
60
117
{
61
- private readonly IList < SetterBinding > _setters = new List < SetterBinding > ( ) ;
118
+ private readonly IList < ISetterBinding > _setters = new List < ISetterBinding > ( ) ;
62
119
63
120
public TargetObject ( Type type )
64
121
{
@@ -67,12 +124,11 @@ public TargetObject(Type type)
67
124
68
125
public Type Type { get ; }
69
126
70
- public SelectedField StartBinding ( string bindingName )
127
+ public BindingTarget StartBinding ( string bindingName )
71
128
{
72
- var setter = new SetterBinding ( bindingName ) ;
73
- _setters . Add ( setter ) ;
74
-
75
- return setter . Field ;
129
+ var bindingTarget = new BindingTarget ( bindingName ) ;
130
+ _setters . Add ( bindingTarget ) ;
131
+ return bindingTarget ;
76
132
}
77
133
78
134
public string ToSelectField ( IFieldMapping fields , ISerializer serializer )
@@ -81,7 +137,12 @@ public string ToSelectField(IFieldMapping fields, ISerializer serializer)
81
137
return $ "jsonb_build_object({ jsonBuildObjectArgs } )";
82
138
}
83
139
84
- private class SetterBinding
140
+ public interface ISetterBinding
141
+ {
142
+ string ToJsonBuildObjectPair ( IFieldMapping mapping , ISerializer serializer ) ;
143
+ }
144
+
145
+ public class SetterBinding : ISetterBinding
85
146
{
86
147
public SetterBinding ( string name )
87
148
{
@@ -101,6 +162,23 @@ public string ToJsonBuildObjectPair(IFieldMapping mapping, ISerializer serialize
101
162
return $ "'{ Name } ', { locator } ";
102
163
}
103
164
}
165
+
166
+ public class SqlProjectionBinding : ISetterBinding
167
+ {
168
+ public SqlProjectionBinding ( string name , ISqlFragment projectionFragment )
169
+ {
170
+ Name = name ;
171
+ ProjectionFragment = projectionFragment ;
172
+ }
173
+
174
+ private string Name { get ; }
175
+ private ISqlFragment ProjectionFragment { get ; }
176
+
177
+ public string ToJsonBuildObjectPair ( IFieldMapping mapping , ISerializer serializer )
178
+ {
179
+ return $ "'{ Name } ', ({ ProjectionFragment . ToSql ( ) } )";
180
+ }
181
+ }
104
182
}
105
183
106
184
public class SelectedField : IEnumerable < MemberInfo >
0 commit comments