Skip to content

Commit 293184a

Browse files
committed
Add AddOrReplaceComponent and use in From
GetOneComponent prioritizes engine
1 parent fdb081b commit 293184a

File tree

2 files changed

+91
-11
lines changed

2 files changed

+91
-11
lines changed

QueryBuilder.Tests/GeneralTests.cs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using SqlKata.Compilers;
22
using SqlKata.Extensions;
33
using SqlKata.Tests.Infrastructure;
4+
using System;
5+
using System.Linq;
46
using Xunit;
57

68
namespace SqlKata.Tests
@@ -205,5 +207,64 @@ public void CompilerSpecificFromMixed()
205207
Assert.Equal("SELECT * FROM \"pgsql\"", c[EngineCodes.PostgreSql].RawSql);
206208
Assert.Equal("SELECT * FROM `mysql`", c[EngineCodes.MySql].RawSql);
207209
}
210+
211+
[Fact]
212+
public void OneFromPerEngine()
213+
{
214+
var query = new Query("generic")
215+
.ForSqlServer(q => q.From("dnu"))
216+
.ForSqlServer(q => q.From("mssql"));
217+
var engines = new[] { EngineCodes.SqlServer, EngineCodes.MySql, EngineCodes.PostgreSql };
218+
var c = Compilers.Compile(engines, query);
219+
220+
Assert.Equal(2, query.Clauses.OfType<AbstractFrom>().Count());
221+
Assert.Equal("SELECT * FROM [mssql]", c[EngineCodes.SqlServer].RawSql);
222+
Assert.Equal("SELECT * FROM \"generic\"", c[EngineCodes.PostgreSql].RawSql);
223+
Assert.Equal("SELECT * FROM `generic`", c[EngineCodes.MySql].RawSql);
224+
}
225+
226+
[Theory]
227+
[InlineData(null, null)]
228+
[InlineData(null, "mssql")]
229+
[InlineData("original", null)]
230+
[InlineData("original", "mssql")]
231+
public void AddOrReplace_Works(string table, string engine)
232+
{
233+
var query = new Query();
234+
if (table != null)
235+
query.From(table);
236+
query.AddOrReplaceComponent("from", new FromClause() { Table = "updated", Engine = engine });
237+
var froms = query.Clauses.OfType<FromClause>();
238+
239+
Assert.Single(froms);
240+
Assert.Equal("updated", froms.Single().Table);
241+
}
242+
243+
[Theory]
244+
[InlineData(null, "generic")]
245+
[InlineData(EngineCodes.SqlServer, "mssql")]
246+
[InlineData(EngineCodes.MySql, "generic")]
247+
public void GetOneComponent_Prefers_Engine(string engine, string column)
248+
{
249+
var query = new Query()
250+
.Where("generic", "foo")
251+
.ForSqlServer(q => q.Where("mssql", "foo"));
252+
253+
var where = query.GetOneComponent("where", engine) as BasicCondition;
254+
255+
Assert.NotNull(where);
256+
Assert.Equal(column, where.Column);
257+
}
258+
259+
[Fact]
260+
public void AddOrReplace_Throws_MoreThanOne()
261+
{
262+
var query = new Query()
263+
.Where("a", "b")
264+
.Where("c", "d");
265+
266+
Action act = () => query.AddOrReplaceComponent("where", new BasicCondition());
267+
Assert.Throws<InvalidOperationException>(act);
268+
}
208269
}
209270
}

QueryBuilder/BaseQuery.cs

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,28 @@ public Q AddComponent(string component, AbstractClause clause, string engineCode
8282
return (Q)this;
8383
}
8484

85+
/// <summary>
86+
/// If the query already contains a clause for the given component
87+
/// and engine, replace it with the specified clause. Otherwise, just
88+
/// add the clause.
89+
/// </summary>
90+
/// <param name="component"></param>
91+
/// <param name="clause"></param>
92+
/// <param name="engineCode"></param>
93+
/// <returns></returns>
94+
public Q AddOrReplaceComponent(string component, AbstractClause clause, string engineCode = null)
95+
{
96+
engineCode = engineCode ?? EngineScope;
97+
98+
var current = GetComponents(component).SingleOrDefault(c => c.Engine == engineCode);
99+
if (current != null)
100+
Clauses.Remove(current);
101+
102+
return AddComponent(component, clause, engineCode);
103+
}
104+
105+
106+
85107
/// <summary>
86108
/// Get the list of clauses for a component.
87109
/// </summary>
@@ -123,13 +145,10 @@ public List<AbstractClause> GetComponents(string component, string engineCode =
123145
/// <returns></returns>
124146
public C GetOneComponent<C>(string component, string engineCode = null) where C : AbstractClause
125147
{
126-
if (engineCode == null)
127-
{
128-
engineCode = EngineScope;
129-
}
148+
engineCode = engineCode ?? EngineScope;
130149

131-
return GetComponents<C>(component, engineCode)
132-
.FirstOrDefault();
150+
var all = GetComponents<C>(component, engineCode);
151+
return all.FirstOrDefault(c => c.Engine == engineCode) ?? all.FirstOrDefault(c => c.Engine == null);
133152
}
134153

135154
/// <summary>
@@ -149,7 +168,7 @@ public AbstractClause GetOneComponent(string component, string engineCode = null
149168
}
150169

151170
/// <summary>
152-
/// Return wether the query has clauses for a component.
171+
/// Return whether the query has clauses for a component.
153172
/// </summary>
154173
/// <param name="component"></param>
155174
/// <param name="engineCode"></param>
@@ -247,9 +266,9 @@ protected bool GetNot()
247266
/// <returns></returns>
248267
public Q From(string table)
249268
{
250-
return ClearComponent("from").AddComponent("from", new FromClause
269+
return AddOrReplaceComponent("from", new FromClause
251270
{
252-
Table = table
271+
Table = table,
253272
});
254273
}
255274

@@ -263,15 +282,15 @@ public Q From(Query query, string alias = null)
263282
query.As(alias);
264283
};
265284

266-
return ClearComponent("from").AddComponent("from", new QueryFromClause
285+
return AddOrReplaceComponent("from", new QueryFromClause
267286
{
268287
Query = query
269288
});
270289
}
271290

272291
public Q FromRaw(string sql, params object[] bindings)
273292
{
274-
return ClearComponent("from").AddComponent("from", new RawFromClause
293+
return AddOrReplaceComponent("from", new RawFromClause
275294
{
276295
Expression = sql,
277296
Bindings = bindings,

0 commit comments

Comments
 (0)