• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

loresoft / FluentCommand / 26594173245

28 May 2026 06:28PM UTC coverage: 55.553% (+0.7%) from 54.902%
26594173245

push

github

pwelter34
Move JSON support, add docs and examples

1358 of 3215 branches covered (42.24%)

Branch coverage included in aggregate %.

103 of 234 new or added lines in 9 files covered. (44.02%)

371 existing lines in 26 files now uncovered.

4389 of 7130 relevant lines covered (61.56%)

312.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.21
/src/FluentCommand/Query/JoinEntityBuilder.cs
1
using System.Linq.Expressions;
2

3
using FluentCommand.Query.Generators;
4
using FluentCommand.Reflection;
5

6
namespace FluentCommand.Query;
7

8
/// <summary>
9
/// Provides a builder for constructing SQL JOIN clauses between two entity types with fluent, chainable methods.
10
/// </summary>
11
/// <typeparam name="TLeft">The entity type of the left join.</typeparam>
12
/// <typeparam name="TRight">The entity type of the right join.</typeparam>
13
public class JoinEntityBuilder<TLeft, TRight> : JoinBuilder<JoinEntityBuilder<TLeft, TRight>>
14
    where TLeft : class
15
    where TRight : class
16
{
17
    private static readonly TypeAccessor _leftAccessor = TypeAccessor.GetAccessor<TLeft>();
11✔
18
    private static readonly TypeAccessor _rightAccessor = TypeAccessor.GetAccessor<TRight>();
11✔
19

20
    /// <summary>
21
    /// Initializes a new instance of the <see cref="JoinEntityBuilder{TLeft, TRight}"/> class.
22
    /// </summary>
23
    /// <param name="queryGenerator">The <see cref="IQueryGenerator"/> used to generate SQL expressions.</param>
24
    /// <param name="parameters">The list of <see cref="QueryParameter"/> objects for the query.</param>
25
    public JoinEntityBuilder(IQueryGenerator queryGenerator, List<QueryParameter> parameters)
26
        : base(queryGenerator, parameters)
12✔
27
    {
28
    }
12✔
29

30
    /// <summary>
31
    /// Specifies the left property to join on using a strongly-typed property expression.
32
    /// </summary>
33
    /// <typeparam name="TValue">The type of the property value.</typeparam>
34
    /// <param name="property">An expression selecting the property on the left entity to join on.</param>
35
    /// <param name="tableAlias">The alias of the left table.</param>
36
    /// <returns>
37
    /// The same builder instance for method chaining.
38
    /// </returns>
39
    public JoinEntityBuilder<TLeft, TRight> Left<TValue>(
40
        Expression<Func<TLeft, TValue>> property,
41
        string tableAlias)
42
    {
43
        var propertyAccessor = GetPropertyAccessor(_leftAccessor, property);
12✔
44

45
        return Left(propertyAccessor.Column, tableAlias);
12✔
46
    }
47

48
    /// <summary>
49
    /// Specifies the right property to join on using a strongly-typed property expression.
50
    /// The table name and schema are inferred from the right entity type.
51
    /// </summary>
52
    /// <typeparam name="TValue">The type of the property value.</typeparam>
53
    /// <param name="property">An expression selecting the property on the right entity to join on.</param>
54
    /// <param name="tableAlias">The alias of the right table.</param>
55
    /// <returns>
56
    /// The same builder instance for method chaining.
57
    /// </returns>
58
    public JoinEntityBuilder<TLeft, TRight> Right<TValue>(
59
        Expression<Func<TRight, TValue>> property,
60
        string tableAlias)
61
    {
62
        var tableName = _rightAccessor.TableName
12!
63
            ?? throw new InvalidOperationException("The right entity table name is not configured.");
12✔
64

65
        return Right(
12✔
66
            property,
12✔
67
            tableName,
12✔
68
            _rightAccessor.TableSchema,
12✔
69
            tableAlias);
12✔
70
    }
71

72
    /// <summary>
73
    /// Specifies the right property to join on using a strongly-typed property expression and explicit table information.
74
    /// </summary>
75
    /// <typeparam name="TValue">The type of the property value.</typeparam>
76
    /// <param name="property">An expression selecting the property on the right entity to join on.</param>
77
    /// <param name="tableName">The name of the right table. If <c>null</c>, the entity mapping is used.</param>
78
    /// <param name="tableSchema">The schema of the right table. If <c>null</c>, the entity mapping is used.</param>
79
    /// <param name="tableAlias">The alias of the right table. If <c>null</c>, the table name is used as the alias.</param>
80
    /// <returns>
81
    /// The same builder instance for method chaining.
82
    /// </returns>
83
    public JoinEntityBuilder<TLeft, TRight> Right<TValue>(
84
        Expression<Func<TRight, TValue>> property,
85
        string? tableName,
86
        string? tableSchema,
87
        string? tableAlias)
88
    {
89
        var propertyAccessor = GetPropertyAccessor(_rightAccessor, property);
12✔
90
        var resolvedTableName = tableName ?? _rightAccessor.TableName
12!
91
            ?? throw new InvalidOperationException("The right entity table name is not configured.");
12✔
92

93
        return Right(
12!
94
            propertyAccessor.Column,
12✔
95
            resolvedTableName,
12✔
96
            tableSchema ?? _rightAccessor.TableSchema,
12✔
97
            tableAlias ?? resolvedTableName);
12✔
98
    }
99

100
    private static IMemberAccessor GetPropertyAccessor<TModel, TValue>(
101
        TypeAccessor typeAccessor,
102
        Expression<Func<TModel, TValue>> property)
103
    {
104
        ArgumentNullException.ThrowIfNull(property);
24✔
105

106
        var propertyAccessor = typeAccessor.FindProperty(property);
24✔
107
        if (propertyAccessor is null)
24!
UNCOV
108
            throw new ArgumentException("The specified property does not exist on the entity.", nameof(property));
×
109

110
        return propertyAccessor;
24✔
111
    }
112
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc