Skip to content

Commit bbdcd80

Browse files
committed
Dynamic definition of compiler containers
Language-dependant ones are included only if basic assembly is loaded
1 parent fdb8fff commit bbdcd80

5 files changed

Lines changed: 512 additions & 2 deletions

File tree

Orm/Xtensive.Orm/Orm/Providers/DomainHandler.cs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
using System;
88
using System.Collections.Generic;
9+
using System.Linq;
10+
using System.Runtime.Loader;
911
using Xtensive.Core;
1012
using Xtensive.Orm.Building.Builders;
1113
using Xtensive.Orm.Linq.MemberCompilation;
@@ -123,7 +125,7 @@ protected virtual IPostCompiler CreatePostCompiler(CompilerConfiguration configu
123125
/// <returns>Compiler containers for current provider.</returns>
124126
protected virtual IEnumerable<Type> GetProviderCompilerContainers()
125127
{
126-
return new[] {
128+
IEnumerable<Type> basicCompilerContainers = new[] {
127129
typeof (NullableCompilers),
128130
typeof (StringCompilers),
129131
typeof (DateTimeCompilers),
@@ -135,10 +137,29 @@ protected virtual IEnumerable<Type> GetProviderCompilerContainers()
135137
typeof (NumericCompilers),
136138
typeof (DecimalCompilers),
137139
typeof (GuidCompilers),
140+
typeof (EnumCompilers),
138141
//typeof (VbStringsCompilers),
139142
//typeof (VbDateAndTimeCompilers),
140-
typeof (EnumCompilers),
141143
};
144+
var result = basicCompilerContainers;
145+
var loadedAssemblies = AssemblyLoadContext.Default.Assemblies;
146+
// dynamic registration to not cause assembly loading
147+
if (loadedAssemblies.Any(a => a.GetName().Name.Equals("FSharp.Core", StringComparison.OrdinalIgnoreCase))) {
148+
result = result.Concat(new[] {
149+
typeof (FSharpMathOperationsCompilers),
150+
typeof (FSharpOperatorsCompilers),
151+
typeof (FSharpStringCompilers),
152+
typeof (FSharpConversionsCompilers),
153+
});
154+
}
155+
//if (loadedAssemblies.Any(a => a.GetName().Name.Equals("Microsoft.VisualBasic", StringComparison.OrdinalIgnoreCase)){
156+
// result = result.Concat(new[] {
157+
// typeof (VbStringsCompilers),
158+
// typeof (VbDateAndTimeCompilers),
159+
// });
160+
//}
161+
162+
return result;
142163
}
143164

144165
protected virtual SearchConditionCompiler CreateSearchConditionVisitor()
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Copyright (C) 2026 Xtensive LLC.
2+
// This code is distributed under MIT license terms.
3+
// See the License.txt file in the project root for more information.
4+
5+
using System.Reflection;
6+
using Xtensive.Sql.Dml;
7+
8+
namespace Xtensive.Orm.Providers
9+
{
10+
#pragma warning disable IDE0060 // Remove unused parameter
11+
[CompilerContainer(typeof(SqlExpression))]
12+
internal static class FSharpConversionsCompilers
13+
{
14+
#if NET10_0_OR_GREATER
15+
private const string FSharpOperators = "Microsoft.FSharp.Core.Operators, FSharp.Core, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
16+
#else
17+
private const string FSharpOperators = "Microsoft.FSharp.Core.Operators, FSharp.Core, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
18+
#endif
19+
20+
[Compiler(FSharpOperators, "ToChar", TargetKind.Static | TargetKind.Method, 1)]
21+
public static SqlExpression ToCharGeneric(MemberInfo memberInfo, SqlExpression stringExpression)
22+
{
23+
return ExpressionTranslationHelpers.ToChar(stringExpression);
24+
}
25+
26+
[Compiler(FSharpOperators, "ToByte", TargetKind.Static | TargetKind.Method, 1)]
27+
public static SqlExpression ToByteGeneric(MemberInfo memberInfo, SqlExpression stringExpression)
28+
{
29+
return ExpressionTranslationHelpers.ToByte(stringExpression);
30+
}
31+
32+
[Compiler(FSharpOperators, "ToSByte", TargetKind.Static | TargetKind.Method, 1)]
33+
public static SqlExpression ToSByteGeneric(MemberInfo memberInfo, SqlExpression stringExpression)
34+
{
35+
return ExpressionTranslationHelpers.ToSbyte(stringExpression);
36+
}
37+
38+
[Compiler(FSharpOperators, "ToInt16", TargetKind.Static | TargetKind.Method, 1)]
39+
public static SqlExpression ToShortGeneric(MemberInfo memberInfo, SqlExpression stringExpression)
40+
{
41+
return ExpressionTranslationHelpers.ToShort(stringExpression);
42+
}
43+
44+
[Compiler(FSharpOperators, "ToUInt16", TargetKind.Static | TargetKind.Method, 1)]
45+
public static SqlExpression ToUShortGeneric(MemberInfo memberInfo, SqlExpression stringExpression)
46+
{
47+
return ExpressionTranslationHelpers.ToUshort(stringExpression);
48+
}
49+
50+
[Compiler(FSharpOperators, "ToInt", TargetKind.Static | TargetKind.Method, 1)]
51+
public static SqlExpression ToIntGeneric(MemberInfo memberInfo, SqlExpression stringExpression)
52+
{
53+
return ExpressionTranslationHelpers.ToInt(stringExpression);
54+
}
55+
56+
[Compiler(FSharpOperators, "ToInt32", TargetKind.Static | TargetKind.Method, 1)]
57+
public static SqlExpression ToInt32Generic(MemberInfo memberInfo, SqlExpression stringExpression)
58+
{
59+
return ExpressionTranslationHelpers.ToInt(stringExpression);
60+
}
61+
62+
[Compiler(FSharpOperators, "ToUInt32", TargetKind.Static | TargetKind.Method, 1)]
63+
public static SqlExpression ToUInt32Generic(MemberInfo memberInfo, SqlExpression stringExpression)
64+
{
65+
return ExpressionTranslationHelpers.ToUint(stringExpression);
66+
}
67+
68+
[Compiler(FSharpOperators, "ToInt64", TargetKind.Static | TargetKind.Method, 1)]
69+
public static SqlExpression ToInt64Generic(MemberInfo memberInfo, SqlExpression stringExpression)
70+
{
71+
return ExpressionTranslationHelpers.ToLong(stringExpression);
72+
}
73+
74+
[Compiler(FSharpOperators, "ToUInt64", TargetKind.Static | TargetKind.Method, 1)]
75+
public static SqlExpression ToUInt64Generic(MemberInfo memberInfo, SqlExpression stringExpression)
76+
{
77+
return ExpressionTranslationHelpers.ToUlong(stringExpression);
78+
}
79+
80+
[Compiler(FSharpOperators, "ToSingle", TargetKind.Static | TargetKind.Method, 1)]
81+
public static SqlExpression ToSingleGeneric(MemberInfo memberInfo, SqlExpression stringExpression)
82+
{
83+
return ExpressionTranslationHelpers.ToFloat(stringExpression);
84+
}
85+
86+
[Compiler(FSharpOperators, "ToDouble", TargetKind.Static | TargetKind.Method, 1)]
87+
public static SqlExpression ToDoubleGeneric(MemberInfo memberInfo, SqlExpression stringExpression)
88+
{
89+
return ExpressionTranslationHelpers.ToDouble(stringExpression);
90+
}
91+
92+
[Compiler(FSharpOperators, "ToDecimal", TargetKind.Static | TargetKind.Method, 1)]
93+
public static SqlExpression ToDecimalGeneric(MemberInfo memberInfo, SqlExpression stringExpression)
94+
{
95+
return ExpressionTranslationHelpers.ToDecimal(stringExpression);
96+
}
97+
98+
[Compiler(FSharpOperators, "ToString", TargetKind.Static | TargetKind.Method, 1)]
99+
public static SqlExpression ToStringGeneric(MemberInfo memberInfo, SqlExpression expression)
100+
101+
{
102+
return ExpressionTranslationHelpers.ToString(expression);
103+
}
104+
}
105+
#pragma warning restore IDE0060 // Remove unused parameter
106+
}
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
// Copyright (C) 2026 Xtensive LLC.
2+
// This code is distributed under MIT license terms.
3+
// See the License.txt file in the project root for more information.
4+
5+
using System;
6+
using System.Reflection;
7+
using Xtensive.Reflection;
8+
using Xtensive.Sql;
9+
using Xtensive.Sql.Dml;
10+
11+
namespace Xtensive.Orm.Providers
12+
{
13+
#pragma warning disable IDE0060 // Remove unused parameter
14+
[CompilerContainer(typeof(SqlExpression))]
15+
internal static class FSharpMathOperationsCompilers
16+
{
17+
#if NET10_0_OR_GREATER
18+
private const string FSharpOperators = "Microsoft.FSharp.Core.Operators, FSharp.Core, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
19+
#else
20+
private const string FSharpOperators = "Microsoft.FSharp.Core.Operators, FSharp.Core, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
21+
#endif
22+
23+
[Compiler(FSharpOperators, "Abs", TargetKind.Static | TargetKind.Method, 1)]
24+
public static SqlExpression AbsGeneric(MemberInfo member, SqlExpression operand)
25+
{
26+
return SqlDml.Abs(operand);
27+
}
28+
29+
[Compiler(FSharpOperators, "Sign", TargetKind.Static | TargetKind.Method, 1)]
30+
public static SqlExpression SignGeneric(MemberInfo member, SqlExpression operand)
31+
{
32+
return ExpressionTranslationHelpers.ToInt(SqlDml.Sign(operand));
33+
}
34+
35+
[Compiler(FSharpOperators, "Acos", TargetKind.Static | TargetKind.Method, 1)]
36+
public static SqlExpression AcosGeneric(MemberInfo member, SqlExpression x)
37+
{
38+
return SqlDml.Acos(x);
39+
}
40+
41+
[Compiler(FSharpOperators, "Asin", TargetKind.Static | TargetKind.Method, 1)]
42+
public static SqlExpression AsinGeneric(MemberInfo member, SqlExpression x)
43+
{
44+
return SqlDml.Asin(x);
45+
}
46+
47+
[Compiler(FSharpOperators, "Atan", TargetKind.Static | TargetKind.Method, 1)]
48+
public static SqlExpression AtanGeneric(MemberInfo member, SqlExpression x)
49+
{
50+
return SqlDml.Atan(x);
51+
}
52+
53+
[Compiler(FSharpOperators, "Atan2", TargetKind.Static | TargetKind.Method, 2)]
54+
public static SqlExpression Atan2Generic(MemberInfo member, SqlExpression x, SqlExpression y)
55+
{
56+
return SqlDml.Atan2(x, y);
57+
}
58+
59+
[Compiler(FSharpOperators, "Ceiling", TargetKind.Static | TargetKind.Method, 1)]
60+
public static SqlExpression CeilingGeneric(MemberInfo member, SqlExpression x)
61+
{
62+
return SqlDml.Ceiling(x);
63+
}
64+
65+
[Compiler(FSharpOperators, "Cos", TargetKind.Static | TargetKind.Method, 1)]
66+
public static SqlExpression CosGeneric(MemberInfo member, SqlExpression x)
67+
{
68+
return SqlDml.Cos(x);
69+
}
70+
71+
[Compiler(FSharpOperators, "Cosh", TargetKind.Static | TargetKind.Method, 1)]
72+
public static SqlExpression CoshGeneric(MemberInfo member, SqlExpression x)
73+
{
74+
return (SqlDml.Exp(x) + SqlDml.Exp(-x)) / SqlDml.Literal(2);
75+
}
76+
77+
[Compiler(FSharpOperators, "Exp", TargetKind.Static | TargetKind.Method, 1)]
78+
public static SqlExpression ExpGeneric(MemberInfo member, SqlExpression x)
79+
{
80+
return SqlDml.Exp(x);
81+
}
82+
83+
[Compiler(FSharpOperators, "Floor", TargetKind.Static | TargetKind.Method, 1)]
84+
public static SqlExpression FloorGeneric(MemberInfo member, SqlExpression x)
85+
{
86+
return SqlDml.Floor(x);
87+
}
88+
89+
[Compiler(FSharpOperators, "Log", TargetKind.Static | TargetKind.Method, 1)]
90+
public static SqlExpression LogGeneric(MemberInfo member, SqlExpression x)
91+
{
92+
return SqlDml.Log(x);
93+
}
94+
95+
[Compiler(FSharpOperators, "Log10", TargetKind.Static | TargetKind.Method, 1)]
96+
public static SqlExpression Log10Generic(MemberInfo member, SqlExpression x)
97+
{
98+
return SqlDml.Log10(x);
99+
}
100+
101+
[Compiler(FSharpOperators, "Max", TargetKind.Static | TargetKind.Method, 1)]
102+
public static SqlExpression MaxGeneric(MemberInfo member, SqlExpression left, SqlExpression right)
103+
{
104+
var result = SqlDml.Case();
105+
_ = result.Add(left > right, left);
106+
result.Else = right;
107+
return result;
108+
}
109+
110+
[Compiler(FSharpOperators, "Min", TargetKind.Static | TargetKind.Method, 1)]
111+
public static SqlExpression MinGeneric(MemberInfo member, SqlExpression left, SqlExpression right)
112+
{
113+
var result = SqlDml.Case();
114+
_ = result.Add(left < right, left);
115+
result.Else = right;
116+
return result;
117+
}
118+
119+
[Compiler(FSharpOperators, "Round", TargetKind.Static | TargetKind.Method, 1)]
120+
public static SqlExpression RoundGeneric(MemberInfo member, SqlExpression x)
121+
{
122+
return BankersRound(x, null, (member as MethodInfo).GetGenericArguments()[0] == WellKnownTypes.Decimal);
123+
}
124+
125+
private static SqlExpression BankersRound(SqlExpression value, SqlExpression digits, bool isDecimal)
126+
{
127+
if (!isDecimal) {
128+
return SqlDml.Round(value, digits, TypeCode.Double, MidpointRounding.ToEven);
129+
}
130+
if (digits == null) {
131+
return TryCastToDecimalPS(SqlDml.Round(value, digits, TypeCode.Decimal, MidpointRounding.ToEven), 28, 0);
132+
}
133+
if (!(digits is SqlLiteral<int> scale)) {
134+
throw new NotSupportedException();
135+
}
136+
return TryCastToDecimalPS(SqlDml.Round(value, digits, TypeCode.Decimal, MidpointRounding.ToEven), 28, Convert.ToInt16(scale.Value));
137+
}
138+
139+
private static SqlExpression TryCastToDecimalPS(SqlExpression value, short precision, short scale)
140+
{
141+
var context = ExpressionTranslationContext.Current;
142+
var provider = context.ProviderInfo.ProviderName;
143+
if (provider.Equals(WellKnown.Provider.PostgreSql, StringComparison.Ordinal)
144+
|| provider.Equals(WellKnown.Provider.Oracle, StringComparison.Ordinal)) {
145+
// to fit result into .Net decimal since Npgsql client libarary does not provide a way to make in on reading
146+
return SqlDml.Cast(value, SqlType.Decimal, precision, scale);
147+
}
148+
return value;
149+
}
150+
151+
152+
[Compiler(FSharpOperators, "Sin", TargetKind.Static | TargetKind.Method, 1)]
153+
public static SqlExpression SinGeneric(MemberInfo member, SqlExpression x)
154+
{
155+
return SqlDml.Sin(x);
156+
}
157+
158+
[Compiler(FSharpOperators, "Sinh", TargetKind.Static | TargetKind.Method, 1)]
159+
public static SqlExpression SinhGeneric(MemberInfo member, SqlExpression x)
160+
{
161+
return (SqlDml.Exp(x) - SqlDml.Exp(-x)) / SqlDml.Literal(2);
162+
}
163+
164+
[Compiler(FSharpOperators, "Sqrt", TargetKind.Static | TargetKind.Method, 2)]
165+
public static SqlExpression SqrtGeneric(MemberInfo member, SqlExpression x)
166+
{
167+
return SqlDml.Sqrt(x);
168+
}
169+
170+
[Compiler(FSharpOperators, "Tan", TargetKind.Static | TargetKind.Method, 1)]
171+
public static SqlExpression TanGeneric(MemberInfo member, SqlExpression x)
172+
{
173+
return SqlDml.Tan(x);
174+
}
175+
176+
[Compiler(FSharpOperators, "Tanh", TargetKind.Static | TargetKind.Method, 1)]
177+
public static SqlExpression TanhGeneric(MemberInfo member, SqlExpression x)
178+
{
179+
var exp2d = SqlDml.Exp(SqlDml.Literal(2) * x);
180+
var one = SqlDml.Literal(1);
181+
182+
return (exp2d - one) / (exp2d + one);
183+
}
184+
185+
[Compiler(FSharpOperators, "Truncate", TargetKind.Static | TargetKind.Method, 1)]
186+
public static SqlExpression TruncateGeneric(MemberInfo member, SqlExpression x)
187+
{
188+
if ((member as MethodInfo).GetGenericArguments()[0] == WellKnownTypes.Decimal)
189+
return TryCastToDecimalPS(SqlDml.Truncate(x), 28, 0);
190+
return SqlDml.Truncate(x);
191+
}
192+
}
193+
#pragma warning restore IDE0060 // Remove unused parameter
194+
}

0 commit comments

Comments
 (0)