Skip to content

Commit 385d3d5

Browse files
Fix Query.Clone() shallow copy of Includes and Variables
- Add Clone() method to Include class for deep copying - Fix Query.Clone() to deep-copy Includes list and Variables dictionary - Fix XQuery.Clone() with same deep-copy fixes - Add unit tests for the clone bug (independent list, objects, dict, properties) Fixes #747 Agent-Logs-Url: https://github.com/sqlkata/querybuilder/sessions/d82ad628-73f5-4c2f-b56e-f4021ce1519f Co-authored-by: ahmad-moussawi <2517523+ahmad-moussawi@users.noreply.github.com>
1 parent 1ad507e commit 385d3d5

File tree

4 files changed

+82
-4
lines changed

4 files changed

+82
-4
lines changed

QueryBuilder.Tests/GeneralTests.cs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,5 +601,70 @@ public void Passing_Negative_Boolean_False_To_Where_Should_Call_WhereTrue_Or_Whe
601601

602602
Assert.Equal("SELECT * FROM [Table] WHERE [Col] != cast(0 as bit)", c[EngineCodes.SqlServer].ToString());
603603
}
604+
605+
[Fact]
606+
public void Clone_ShouldProduceIndependentIncludesList()
607+
{
608+
var query = new Query("users")
609+
.Include("posts", new Query("posts"), "user_id", "id");
610+
611+
var clone = query.Clone();
612+
613+
// Adding an include to the clone should not affect the original
614+
clone.Include("comments", new Query("comments"), "user_id", "id");
615+
616+
Assert.Single(query.Includes);
617+
Assert.Equal(2, clone.Includes.Count);
618+
}
619+
620+
[Fact]
621+
public void Clone_ShouldProduceIndependentIncludeObjects()
622+
{
623+
var query = new Query("users")
624+
.Include("posts", new Query("posts"), "user_id", "id");
625+
626+
var clone = query.Clone();
627+
628+
// Modifying an include property on the clone should not affect the original
629+
clone.Includes[0].Name = "modified_name";
630+
631+
Assert.Equal("posts", query.Includes[0].Name);
632+
Assert.Equal("modified_name", clone.Includes[0].Name);
633+
}
634+
635+
[Fact]
636+
public void Clone_ShouldProduceIndependentVariablesDictionary()
637+
{
638+
var query = new Query("users").Define("limit", 10);
639+
640+
var clone = query.Clone();
641+
642+
// Adding a variable to the clone should not affect the original
643+
clone.Define("offset", 5);
644+
645+
Assert.False(query.Variables.ContainsKey("offset"));
646+
Assert.True(clone.Variables.ContainsKey("offset"));
647+
}
648+
649+
[Fact]
650+
public void Clone_ShouldPreserveAllProperties()
651+
{
652+
var query = new Query("users")
653+
.Select("id", "name")
654+
.Where("active", true)
655+
.Distinct()
656+
.As("u")
657+
.Include("posts", new Query("posts"), "user_id", "id")
658+
.Define("myvar", 42);
659+
660+
var clone = query.Clone();
661+
662+
Assert.Equal(query.QueryAlias, clone.QueryAlias);
663+
Assert.Equal(query.IsDistinct, clone.IsDistinct);
664+
Assert.Equal(query.Method, clone.Method);
665+
Assert.Equal(query.Includes.Count, clone.Includes.Count);
666+
Assert.Equal(query.Includes[0].Name, clone.Includes[0].Name);
667+
Assert.Equal(query.Variables["myvar"], clone.Variables["myvar"]);
668+
}
604669
}
605670
}

QueryBuilder/Include.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,17 @@ public class Include
77
public string ForeignKey { get; set; }
88
public string LocalKey { get; set; }
99
public bool IsMany { get; set; }
10+
11+
public Include Clone()
12+
{
13+
return new Include
14+
{
15+
Name = Name,
16+
Query = Query.Clone(),
17+
ForeignKey = ForeignKey,
18+
LocalKey = LocalKey,
19+
IsMany = IsMany,
20+
};
21+
}
1022
}
1123
}

QueryBuilder/Query.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ public override Query Clone()
5555
clone.QueryAlias = QueryAlias;
5656
clone.IsDistinct = IsDistinct;
5757
clone.Method = Method;
58-
clone.Includes = Includes;
59-
clone.Variables = Variables;
58+
clone.Includes = Includes.Select(i => i.Clone()).ToList();
59+
clone.Variables = new Dictionary<string, object>(Variables);
6060
return clone;
6161
}
6262

SqlKata.Execution/XQuery.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Data;
34
using System.Linq;
45
using SqlKata.Compilers;
@@ -35,8 +36,8 @@ public override Query Clone()
3536
query.QueryAlias = QueryAlias;
3637
query.IsDistinct = IsDistinct;
3738
query.Method = Method;
38-
query.Includes = Includes;
39-
query.Variables = Variables;
39+
query.Includes = Includes.Select(i => i.Clone()).ToList();
40+
query.Variables = new Dictionary<string, object>(Variables);
4041

4142
query.SetEngineScope(EngineScope);
4243

0 commit comments

Comments
 (0)