Implement snapshot version history

This commit is contained in:
Codex
2026-09-13 14:28:43 +02:00
parent e28d45ae18
commit 8bdebc5c24
3 changed files with 50 additions and 1 deletions
@@ -324,6 +324,25 @@ public extension SongProject {
vocalists[index].assignedSections.removeAll { $0 == sectionID } vocalists[index].assignedSections.removeAll { $0 == sectionID }
} }
mutating func createVersion(
id: String = UUID().uuidString,
label: String,
createdAt: Date = Date()
) -> SongVersion {
let version = SongVersion(
id: id,
label: label,
snapshot: SongProjectSnapshot(project: self),
createdAt: createdAt
)
versions.append(version)
return version
}
func version(id versionID: String) -> SongVersion? {
versions.first { $0.id == versionID }
}
mutating func appendSection(_ section: SongSection) { mutating func appendSection(_ section: SongSection) {
var orderedSection = section var orderedSection = section
orderedSection.order = nextSectionOrder orderedSection.order = nextSectionOrder
@@ -89,6 +89,36 @@ final class SongProjectModelTests: XCTestCase {
XCTAssertEqual(version.snapshot.instruments, project.instruments) XCTAssertEqual(version.snapshot.instruments, project.instruments)
} }
func testVersionHistoryStoresIndependentSnapshots() {
var project = SongProject(
id: "versioned-project",
title: "First Title",
idea: "Original idea",
genres: [GenreStyle(id: "folk", name: "Folk")]
)
let createdAt = Date(timeIntervalSince1970: 500)
let version = project.createVersion(
id: "version-1",
label: "Initial snapshot",
createdAt: createdAt
)
project.title = "Changed Title"
project.idea = "Changed idea"
project.selectGenreStyle(GenreStyle(id: "electronic", name: "Electronic"))
XCTAssertEqual(project.versions.count, 1)
XCTAssertEqual(project.version(id: "version-1"), version)
XCTAssertEqual(project.versions.first?.label, "Initial snapshot")
XCTAssertEqual(project.versions.first?.createdAt, createdAt)
XCTAssertEqual(project.versions.first?.snapshot.title, "First Title")
XCTAssertEqual(project.versions.first?.snapshot.idea, "Original idea")
XCTAssertEqual(project.versions.first?.snapshot.genres, [GenreStyle(id: "folk", name: "Folk")])
XCTAssertEqual(project.title, "Changed Title")
XCTAssertEqual(project.genres.map(\.id), ["folk", "electronic"])
}
func testGenreStylesAreModeledAsMultiSelect() { func testGenreStylesAreModeledAsMultiSelect() {
let arabicPop = GenreStyle(id: "arabic-pop", name: "Arabic Pop") let arabicPop = GenreStyle(id: "arabic-pop", name: "Arabic Pop")
let synthwave = GenreStyle(id: "synthwave", name: "Synthwave") let synthwave = GenreStyle(id: "synthwave", name: "Synthwave")
+1 -1
View File
@@ -34,7 +34,7 @@ requirement is missing and blocks implementation, record it in
- [x] Create new/open/save song projects locally. - [x] Create new/open/save song projects locally.
- [x] Implement project list. - [x] Implement project list.
- [ ] Implement immutable or snapshot-based version history. - [x] Implement immutable or snapshot-based version history.
- [ ] Restore a previous version without destroying later versions. - [ ] Restore a previous version without destroying later versions.
- [ ] Add autosave strategy that does not create excessive versions. - [ ] Add autosave strategy that does not create excessive versions.