Skip to content

Commit bbbb55f

Browse files
committed
fix: bulk save TPH fallback support not matching props specifically enough.
1 parent 27608c1 commit bbbb55f

File tree

9 files changed

+421
-1
lines changed

9 files changed

+421
-1
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# 5.3.8
2+
3+
- Fix error in bulk saves where inheritance workaround added in 5.3.6 was not specific enough.
4+
15
# 5.3.7
26

37
- Fix error in bulk saves where children of a model that has been `$remove()`'d where neither the children nor the removed model have PKs would still attempt to create.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System.Collections.Generic;
2+
3+
namespace IntelliTect.Coalesce.Tests.TargetClasses.TestDbContext
4+
{
5+
public class MultipleParents
6+
{
7+
public int Id { get; set; }
8+
9+
public int? Parent1Id { get; set; }
10+
public Parent1 Parent1 { get; set; }
11+
12+
public int? Parent2Id { get; set; }
13+
public Parent2 Parent2 { get; set; }
14+
}
15+
16+
public class Parent1
17+
{
18+
public int Id { get; set; }
19+
public List<MultipleParents> Children { get; set; }
20+
}
21+
22+
public class Parent2
23+
{
24+
public int Id { get; set; }
25+
public List<MultipleParents> Children { get; set; }
26+
}
27+
}

src/IntelliTect.Coalesce.Tests/TargetClasses/TestDbContext/TestDbContext.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ public class AppDbContext : DbContext
4343
public DbSet<OneToOneChild2> OneToOneChild2s { get; set; }
4444
public DbSet<OneToOneManyChildren> OneToOneManyChildren { get; set; }
4545

46+
public DbSet<MultipleParents> MultipleParents { get; set; }
47+
public DbSet<Parent1> Parent1s { get; set; }
48+
public DbSet<Parent2> Parent2s { get; set; }
49+
4650

4751
public AppDbContext() : this(Guid.NewGuid().ToString()) { }
4852

src/coalesce-vue/src/viewmodel.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -749,7 +749,14 @@ export abstract class ViewModel<
749749
// The collection is the same collection, but has a different metadata instance
750750
// so direct equality won't work.
751751
(collection.$metadata.name == prop.inverseNavigation?.name &&
752-
collection.$metadata.type == prop.inverseNavigation.type))
752+
collection.$metadata.type == prop.inverseNavigation.type &&
753+
//@ts-expect-error
754+
collection.$metadata.itemType?.typeDef ==
755+
//@ts-expect-error
756+
prop.inverseNavigation.itemType?.typeDef &&
757+
//@ts-expect-error
758+
collection.$metadata.foreignKey?.name ==
759+
prop.inverseNavigation.foreignKey?.name))
753760
) {
754761
// The reference navigation property has no value,
755762
// and the foreign key has no value,

src/coalesce-vue/test/viewmodel.spec.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ import {
3838
TestViewModel,
3939
ZipCodeViewModel,
4040
AbstractImpl1ViewModel,
41+
MultipleParentsViewModel,
42+
Parent1ViewModel,
43+
Parent2ViewModel,
4144
} from "../../test-targets/viewmodels.g";
4245
import {
4346
StudentViewModel,
@@ -1450,6 +1453,59 @@ describe("ViewModel", () => {
14501453
bulkSaveEndpoint.destroy();
14511454
});
14521455

1456+
test("child with multiple parents that reference child by same-named collection navigation", async () => {
1457+
// This test tests that the TPH type variance allowances aren't too permissive when
1458+
// comparing navigation properties by name.
1459+
1460+
const bulkSaveEndpoint = mockEndpoint(
1461+
"/Parent1/bulkSave",
1462+
vitest.fn((req) => ({
1463+
wasSuccessful: true,
1464+
object: null,
1465+
}))
1466+
);
1467+
1468+
const vm = new Parent1ViewModel({
1469+
children: [{}],
1470+
});
1471+
1472+
// Preconditions:
1473+
// Navigation property from the child must not be set,
1474+
// forcing bulk save to find the parent via `$parent.
1475+
expect(vm.children[0].parent1).toBeNull();
1476+
// There should be a collection nav on the other parent with the same name
1477+
expect(new Parent2ViewModel().$metadata.props.children.name).toBe(
1478+
vm.$metadata.props.children.name
1479+
);
1480+
1481+
await vm.$bulkSave();
1482+
1483+
const data = JSON.parse(bulkSaveEndpoint.mock.calls[0][0].data);
1484+
expect(data.items[1].refs).not.toHaveProperty("parent2Id");
1485+
expect(JSON.parse(bulkSaveEndpoint.mock.calls[0][0].data)).toMatchObject({
1486+
items: [
1487+
{
1488+
action: "save",
1489+
type: "Parent1",
1490+
data: { id: null },
1491+
refs: { id: vm.$stableId },
1492+
root: true,
1493+
},
1494+
{
1495+
action: "save",
1496+
type: "MultipleParents",
1497+
data: { id: null },
1498+
refs: {
1499+
id: vm.children[0].$stableId,
1500+
parent1Id: vm.$stableId,
1501+
},
1502+
},
1503+
],
1504+
});
1505+
1506+
bulkSaveEndpoint.destroy();
1507+
});
1508+
14531509
test("added children, then removed, do not attempt to create", async () => {
14541510
const bulkSaveEndpoint = mockEndpoint(
14551511
"/Person/bulkSave",

src/test-targets/api-clients.g.ts

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/test-targets/metadata.g.ts

Lines changed: 143 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)