(
collections: Iterable<Collection<T, O>>,
options?: DriverMethodOptions,
)
| 1695 | } |
| 1696 | |
| 1697 | override async syncCollections<T extends object, O extends object>( |
| 1698 | collections: Iterable<Collection<T, O>>, |
| 1699 | options?: DriverMethodOptions, |
| 1700 | ): Promise<void> { |
| 1701 | const groups = {} as Dictionary<PivotCollectionPersister<any>>; |
| 1702 | |
| 1703 | for (const coll of collections) { |
| 1704 | const wrapped = helper(coll.owner); |
| 1705 | const meta = wrapped.__meta; |
| 1706 | const pks = wrapped.getPrimaryKeys(true)!; |
| 1707 | const snap = coll.getSnapshot(); |
| 1708 | const includes = <T>(arr: T[][], item: T[]) => !!arr.find(i => this.comparePrimaryKeyArrays(i, item)); |
| 1709 | // For union-target polymorphic M:N, prepend the per-row discriminator value so the pivot |
| 1710 | // persister can write it alongside the FK id. Memoized per sync-run because a collection can |
| 1711 | // hold hundreds of items of the same few types, and findDiscriminatorValue walks the prototype |
| 1712 | // chain + re-scans Object.entries each call. |
| 1713 | const isUnionTargetMN = QueryHelper.isUnionTargetPolymorphic(coll.property); |
| 1714 | const classToDisc = new Map<Function, Primary<any>>(); |
| 1715 | const toDiff = (item: AnyEntity) => { |
| 1716 | const keys = helper(item).getPrimaryKeys(true)!; |
| 1717 | if (!isUnionTargetMN) { |
| 1718 | return keys; |
| 1719 | } |
| 1720 | let disc = classToDisc.get(item.constructor); |
| 1721 | if (!classToDisc.has(item.constructor)) { |
| 1722 | disc = QueryHelper.findDiscriminatorValue(coll.property.discriminatorMap!, item.constructor) as Primary<any>; |
| 1723 | |
| 1724 | if (disc === undefined) { |
| 1725 | throw new Error( |
| 1726 | `Cannot resolve discriminator value for ${item.constructor.name} in ${coll.property.name}; the class is not part of the union target list.`, |
| 1727 | ); |
| 1728 | } |
| 1729 | |
| 1730 | classToDisc.set(item.constructor, disc); |
| 1731 | } |
| 1732 | return [disc as Primary<any>, ...keys]; |
| 1733 | }; |
| 1734 | const snapshot = snap ? snap.map(toDiff) : []; |
| 1735 | const current = coll.getItems(false).map(toDiff); |
| 1736 | const deleteDiff = snap ? snapshot.filter(item => !includes(current, item)) : true; |
| 1737 | const insertDiff = current.filter(item => !includes(snapshot, item)); |
| 1738 | const target = snapshot.filter(item => includes(current, item)).concat(...insertDiff); |
| 1739 | const equals = Utils.equals(current, target); |
| 1740 | |
| 1741 | // wrong order if we just delete and insert to the end (only owning sides can have fixed order) |
| 1742 | if (coll.property.owner && coll.property.fixedOrder && !equals && Array.isArray(deleteDiff)) { |
| 1743 | deleteDiff.length = insertDiff.length = 0; |
| 1744 | |
| 1745 | for (const item of snapshot) { |
| 1746 | deleteDiff.push(item); |
| 1747 | } |
| 1748 | |
| 1749 | for (const item of current) { |
| 1750 | insertDiff.push(item); |
| 1751 | } |
| 1752 | } |
| 1753 | |
| 1754 | if (coll.property.kind === ReferenceKind.ONE_TO_MANY) { |
nothing calls this directly
no test coverage detected