From 2f93ee759162bfe432f75dcec1aed28f9af87b78 Mon Sep 17 00:00:00 2001 From: John Estropia Date: Thu, 17 Sep 2020 23:21:41 +0900 Subject: [PATCH] Migrations demo done --- Demo/Demo.xcodeproj/project.pbxproj | 66 ++++- .../Helpers/Menu/Menu.MainView.swift | 5 +- .../Advanced.EvolutionDemo.CreatureType.swift | 8 +- .../Advanced.EvolutionDemo.CreaturesDataSource.swift | 165 +++++++++++++ .../Advanced.EvolutionDemo.GeologicalPeriod.swift | 66 ++++- .../EvolutionDemo/Advanced.EvolutionDemo.ItemView.swift | 72 +++++- .../EvolutionDemo/Advanced.EvolutionDemo.ListView.swift | 96 +++++++- .../EvolutionDemo/Advanced.EvolutionDemo.MainView.swift | 75 +++++- .../EvolutionDemo/Advanced.EvolutionDemo.Migrator.swift | 226 +++++++++++++++--- .../Advanced.EvolutionDemo.ProgressView.swift | 127 ++++++++++ .../Advanced.EvolutionDemo.V1.Creature.swift | 25 ++ .../EvolutionDemo/Advanced.EvolutionDemo.V1.FromV2.swift | 27 +++ .../xcmapping.xml | 81 +++++++ .../EvolutionDemo/Advanced.EvolutionDemo.V1.swift | 2 +- .../Advanced.EvolutionDemo.V2.Creature.swift | 25 ++ .../EvolutionDemo/Advanced.EvolutionDemo.V2.FromV1.swift | 27 +++ .../xcmapping.xml | 97 ++++++++ .../Advanced.EvolutionDemo.V2.FromV1MigrationPolicy.swift | 40 ++++ .../EvolutionDemo/Advanced.EvolutionDemo.V2.FromV3.swift | 41 ++++ .../EvolutionDemo/Advanced.EvolutionDemo.V2.swift | 4 +- .../Advanced.EvolutionDemo.V3.Creature.swift | 25 ++ .../EvolutionDemo/Advanced.EvolutionDemo.V3.FromV2.swift | 43 ++++ .../EvolutionDemo/Advanced.EvolutionDemo.V3.FromV4.swift | 33 +++ .../EvolutionDemo/Advanced.EvolutionDemo.V3.swift | 2 +- .../Advanced.EvolutionDemo.V4.Creature.swift | 25 ++ .../EvolutionDemo/Advanced.EvolutionDemo.V4.FromV3.swift | 44 ++++ .../EvolutionDemo/Advanced.EvolutionDemo.V4.swift | 2 +- .../EvolutionDemo/Advanced.EvolutionDemo.swift | 2 +- Sources/DynamicObject.swift | 9 +- 29 files changed, 1399 insertions(+), 61 deletions(-) create mode 100644 Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.CreaturesDataSource.swift create mode 100644 Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.ProgressView.swift create mode 100644 Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V1.FromV2.swift create mode 100644 Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V1.FromV2.xcmappingmodel/xcmapping.xml create mode 100644 Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V2.FromV1.swift create mode 100644 Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V2.FromV1.xcmappingmodel/xcmapping.xml create mode 100644 Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V2.FromV1MigrationPolicy.swift create mode 100644 Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V2.FromV3.swift create mode 100644 Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V3.FromV2.swift create mode 100644 Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V3.FromV4.swift create mode 100644 Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V4.FromV3.swift diff --git a/Demo/Demo.xcodeproj/project.pbxproj b/Demo/Demo.xcodeproj/project.pbxproj index c71d04b..2d4cadc 100644 --- a/Demo/Demo.xcodeproj/project.pbxproj +++ b/Demo/Demo.xcodeproj/project.pbxproj @@ -11,10 +11,20 @@ B531EFE924EB5A53005F247D /* ⭐️Modern.PokedexDemo.PokedexEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = B531EFE824EB5A52005F247D /* ⭐️Modern.PokedexDemo.PokedexEntry.swift */; }; B531EFEB24EB5ECD005F247D /* ⭐️Modern.PokedexDemo.Service.swift in Sources */ = {isa = PBXBuildFile; fileRef = B531EFEA24EB5ECD005F247D /* ⭐️Modern.PokedexDemo.Service.swift */; }; B531EFED24EB7453005F247D /* Modern.PokedexDemo.MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B531EFEC24EB7453005F247D /* Modern.PokedexDemo.MainView.swift */; }; + B54D2F7A25119540004BEC7D /* Advanced.EvolutionDemo.V2.FromV1.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = B54D2F7925119540004BEC7D /* Advanced.EvolutionDemo.V2.FromV1.xcmappingmodel */; }; + B54D2F7C251196B6004BEC7D /* Advanced.EvolutionDemo.V2.FromV1MigrationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54D2F7B251196B6004BEC7D /* Advanced.EvolutionDemo.V2.FromV1MigrationPolicy.swift */; }; + B54D2F7E25119DCE004BEC7D /* Advanced.EvolutionDemo.V1.FromV2.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = B54D2F7D25119DCE004BEC7D /* Advanced.EvolutionDemo.V1.FromV2.xcmappingmodel */; }; + B54D2F852511B70B004BEC7D /* Advanced.EvolutionDemo.CreaturesDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54D2F842511B70B004BEC7D /* Advanced.EvolutionDemo.CreaturesDataSource.swift */; }; B566C8E824F9D406001134A1 /* Modern.PokedexDemo.ListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B566C8E724F9D406001134A1 /* Modern.PokedexDemo.ListView.swift */; }; B566C8EA24F9D412001134A1 /* Modern.PokedexDemo.ListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B566C8E924F9D412001134A1 /* Modern.PokedexDemo.ListViewController.swift */; }; B566C8EC24F9D694001134A1 /* Modern.PokedexDemo.ItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B566C8EB24F9D694001134A1 /* Modern.PokedexDemo.ItemCell.swift */; }; B566C8EE24FA1EA3001134A1 /* Modern.PokedexDemo.Details.swift in Sources */ = {isa = PBXBuildFile; fileRef = B566C8ED24FA1EA3001134A1 /* Modern.PokedexDemo.Details.swift */; }; + B5931B4225124756007DA58E /* Advanced.EvolutionDemo.V1.FromV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5931B4125124756007DA58E /* Advanced.EvolutionDemo.V1.FromV2.swift */; }; + B5931B442512480A007DA58E /* Advanced.EvolutionDemo.V2.FromV1.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5931B432512480A007DA58E /* Advanced.EvolutionDemo.V2.FromV1.swift */; }; + B5931B46251248B0007DA58E /* Advanced.EvolutionDemo.V3.FromV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5931B45251248B0007DA58E /* Advanced.EvolutionDemo.V3.FromV2.swift */; }; + B5931B4825124940007DA58E /* Advanced.EvolutionDemo.V4.FromV3.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5931B4725124940007DA58E /* Advanced.EvolutionDemo.V4.FromV3.swift */; }; + B5931B4A25124993007DA58E /* Advanced.EvolutionDemo.V3.FromV4.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5931B4925124993007DA58E /* Advanced.EvolutionDemo.V3.FromV4.swift */; }; + B5931B4C251249EE007DA58E /* Advanced.EvolutionDemo.V2.FromV3.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5931B4B251249EE007DA58E /* Advanced.EvolutionDemo.V2.FromV3.swift */; }; B5A3911D24E5429200E7E8BD /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3911C24E5429200E7E8BD /* AppDelegate.swift */; }; B5A3911F24E5429200E7E8BD /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3911E24E5429200E7E8BD /* SceneDelegate.swift */; }; B5A3912124E5429200E7E8BD /* Menu.MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3912024E5429200E7E8BD /* Menu.MainView.swift */; }; @@ -86,6 +96,7 @@ B5A5440925049489000DC5E3 /* Advanced.EvolutionDemo.V2.Creature.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A5440825049489000DC5E3 /* Advanced.EvolutionDemo.V2.Creature.swift */; }; B5A5440B25049492000DC5E3 /* Advanced.EvolutionDemo.V3.Creature.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A5440A25049492000DC5E3 /* Advanced.EvolutionDemo.V3.Creature.swift */; }; B5A5440D2504949C000DC5E3 /* Advanced.EvolutionDemo.V4.Creature.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A5440C2504949C000DC5E3 /* Advanced.EvolutionDemo.V4.Creature.swift */; }; + B5C18F3325138700001BEFB3 /* Advanced.EvolutionDemo.ProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C18F3225138700001BEFB3 /* Advanced.EvolutionDemo.ProgressView.swift */; }; B5D6F1F8250E07FD00DF5D2F /* Advanced.EvolutionDemo.V1.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D6F1F7250E07FD00DF5D2F /* Advanced.EvolutionDemo.V1.swift */; }; B5D6F1FC250E0B1700DF5D2F /* Advanced.EvolutionDemo.V2.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D6F1FB250E0B1700DF5D2F /* Advanced.EvolutionDemo.V2.swift */; }; B5D6F1FE250E0B3F00DF5D2F /* Advanced.EvolutionDemo.GeologicalPeriod.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D6F1FD250E0B3F00DF5D2F /* Advanced.EvolutionDemo.GeologicalPeriod.swift */; }; @@ -118,10 +129,20 @@ B531EFE824EB5A52005F247D /* ⭐️Modern.PokedexDemo.PokedexEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "⭐️Modern.PokedexDemo.PokedexEntry.swift"; sourceTree = ""; }; B531EFEA24EB5ECD005F247D /* ⭐️Modern.PokedexDemo.Service.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "⭐️Modern.PokedexDemo.Service.swift"; sourceTree = ""; }; B531EFEC24EB7453005F247D /* Modern.PokedexDemo.MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.PokedexDemo.MainView.swift; sourceTree = ""; }; + B54D2F7925119540004BEC7D /* Advanced.EvolutionDemo.V2.FromV1.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = Advanced.EvolutionDemo.V2.FromV1.xcmappingmodel; sourceTree = ""; }; + B54D2F7B251196B6004BEC7D /* Advanced.EvolutionDemo.V2.FromV1MigrationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V2.FromV1MigrationPolicy.swift; sourceTree = ""; }; + B54D2F7D25119DCE004BEC7D /* Advanced.EvolutionDemo.V1.FromV2.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = Advanced.EvolutionDemo.V1.FromV2.xcmappingmodel; sourceTree = ""; }; + B54D2F842511B70B004BEC7D /* Advanced.EvolutionDemo.CreaturesDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.CreaturesDataSource.swift; sourceTree = ""; }; B566C8E724F9D406001134A1 /* Modern.PokedexDemo.ListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.PokedexDemo.ListView.swift; sourceTree = ""; }; B566C8E924F9D412001134A1 /* Modern.PokedexDemo.ListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.PokedexDemo.ListViewController.swift; sourceTree = ""; }; B566C8EB24F9D694001134A1 /* Modern.PokedexDemo.ItemCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.PokedexDemo.ItemCell.swift; sourceTree = ""; }; B566C8ED24FA1EA3001134A1 /* Modern.PokedexDemo.Details.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.PokedexDemo.Details.swift; sourceTree = ""; }; + B5931B4125124756007DA58E /* Advanced.EvolutionDemo.V1.FromV2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V1.FromV2.swift; sourceTree = ""; }; + B5931B432512480A007DA58E /* Advanced.EvolutionDemo.V2.FromV1.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V2.FromV1.swift; sourceTree = ""; }; + B5931B45251248B0007DA58E /* Advanced.EvolutionDemo.V3.FromV2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V3.FromV2.swift; sourceTree = ""; }; + B5931B4725124940007DA58E /* Advanced.EvolutionDemo.V4.FromV3.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V4.FromV3.swift; sourceTree = ""; }; + B5931B4925124993007DA58E /* Advanced.EvolutionDemo.V3.FromV4.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V3.FromV4.swift; sourceTree = ""; }; + B5931B4B251249EE007DA58E /* Advanced.EvolutionDemo.V2.FromV3.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V2.FromV3.swift; sourceTree = ""; }; B5A3911924E5429200E7E8BD /* Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Demo.app; sourceTree = BUILT_PRODUCTS_DIR; }; B5A3911C24E5429200E7E8BD /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; B5A3911E24E5429200E7E8BD /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; @@ -192,6 +213,7 @@ B5A5440825049489000DC5E3 /* Advanced.EvolutionDemo.V2.Creature.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V2.Creature.swift; sourceTree = ""; }; B5A5440A25049492000DC5E3 /* Advanced.EvolutionDemo.V3.Creature.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V3.Creature.swift; sourceTree = ""; }; B5A5440C2504949C000DC5E3 /* Advanced.EvolutionDemo.V4.Creature.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V4.Creature.swift; sourceTree = ""; }; + B5C18F3225138700001BEFB3 /* Advanced.EvolutionDemo.ProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.ProgressView.swift; sourceTree = ""; }; B5D6F1F7250E07FD00DF5D2F /* Advanced.EvolutionDemo.V1.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V1.swift; sourceTree = ""; }; B5D6F1FB250E0B1700DF5D2F /* Advanced.EvolutionDemo.V2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.V2.swift; sourceTree = ""; }; B5D6F1FD250E0B3F00DF5D2F /* Advanced.EvolutionDemo.GeologicalPeriod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Advanced.EvolutionDemo.GeologicalPeriod.swift; sourceTree = ""; }; @@ -516,6 +538,8 @@ B5A54400250487C7000DC5E3 /* Advanced.EvolutionDemo.ListView.swift */, B5A54402250487D4000DC5E3 /* Advanced.EvolutionDemo.ItemView.swift */, B5D6F208250E14AA00DF5D2F /* Advanced.EvolutionDemo.Migrator.swift */, + B5C18F3225138700001BEFB3 /* Advanced.EvolutionDemo.ProgressView.swift */, + B54D2F842511B70B004BEC7D /* Advanced.EvolutionDemo.CreaturesDataSource.swift */, B5A543FD25048794000DC5E3 /* Models */, ); path = EvolutionDemo; @@ -554,6 +578,8 @@ children = ( B5D6F1F7250E07FD00DF5D2F /* Advanced.EvolutionDemo.V1.swift */, B5A5440625049480000DC5E3 /* Advanced.EvolutionDemo.V1.Creature.swift */, + B5931B4125124756007DA58E /* Advanced.EvolutionDemo.V1.FromV2.swift */, + B54D2F7D25119DCE004BEC7D /* Advanced.EvolutionDemo.V1.FromV2.xcmappingmodel */, ); name = V1; sourceTree = ""; @@ -563,6 +589,10 @@ children = ( B5D6F1FB250E0B1700DF5D2F /* Advanced.EvolutionDemo.V2.swift */, B5A5440825049489000DC5E3 /* Advanced.EvolutionDemo.V2.Creature.swift */, + B5931B432512480A007DA58E /* Advanced.EvolutionDemo.V2.FromV1.swift */, + B54D2F7925119540004BEC7D /* Advanced.EvolutionDemo.V2.FromV1.xcmappingmodel */, + B54D2F7B251196B6004BEC7D /* Advanced.EvolutionDemo.V2.FromV1MigrationPolicy.swift */, + B5931B4B251249EE007DA58E /* Advanced.EvolutionDemo.V2.FromV3.swift */, ); name = V2; sourceTree = ""; @@ -572,6 +602,8 @@ children = ( B5D6F204250E0DD600DF5D2F /* Advanced.EvolutionDemo.V3.swift */, B5A5440A25049492000DC5E3 /* Advanced.EvolutionDemo.V3.Creature.swift */, + B5931B45251248B0007DA58E /* Advanced.EvolutionDemo.V3.FromV2.swift */, + B5931B4925124993007DA58E /* Advanced.EvolutionDemo.V3.FromV4.swift */, ); name = V3; sourceTree = ""; @@ -581,6 +613,7 @@ children = ( B5D6F206250E0E3B00DF5D2F /* Advanced.EvolutionDemo.V4.swift */, B5A5440C2504949C000DC5E3 /* Advanced.EvolutionDemo.V4.Creature.swift */, + B5931B4725124940007DA58E /* Advanced.EvolutionDemo.V4.FromV3.swift */, ); name = V4; sourceTree = ""; @@ -675,26 +708,26 @@ B5A391B124E96AF600E7E8BD /* Modern.PokedexDemo.swift in Sources */, B5A3918324E7A21800E7E8BD /* Modern.TimeZonesDemo.swift in Sources */, B5A3915E24E6922E00E7E8BD /* ⭐️Modern.PlacemarksDemo.swift in Sources */, - B5D6F207250E0E3B00DF5D2F /* Advanced.EvolutionDemo.V4.swift in Sources */, B5A54405250487F5000DC5E3 /* Advanced.EvolutionDemo.CreatureType.swift in Sources */, - B5A5440725049480000DC5E3 /* Advanced.EvolutionDemo.V1.Creature.swift in Sources */, + B54D2F852511B70B004BEC7D /* Advanced.EvolutionDemo.CreaturesDataSource.swift in Sources */, B5D6F1FE250E0B3F00DF5D2F /* Advanced.EvolutionDemo.GeologicalPeriod.swift in Sources */, - B5A5440925049489000DC5E3 /* Advanced.EvolutionDemo.V2.Creature.swift in Sources */, - B5A5440B25049492000DC5E3 /* Advanced.EvolutionDemo.V3.Creature.swift in Sources */, - B5A5440D2504949C000DC5E3 /* Advanced.EvolutionDemo.V4.Creature.swift in Sources */, B5A54403250487D5000DC5E3 /* Advanced.EvolutionDemo.ItemView.swift in Sources */, - B5D6F1F8250E07FD00DF5D2F /* Advanced.EvolutionDemo.V1.swift in Sources */, B5A54401250487C7000DC5E3 /* Advanced.EvolutionDemo.ListView.swift in Sources */, B5A543FF250487B1000DC5E3 /* Advanced.EvolutionDemo.MainView.swift in Sources */, + B5D6F209250E14AA00DF5D2F /* Advanced.EvolutionDemo.Migrator.swift in Sources */, + B5C18F3325138700001BEFB3 /* Advanced.EvolutionDemo.ProgressView.swift in Sources */, + B5D6F1F8250E07FD00DF5D2F /* Advanced.EvolutionDemo.V1.swift in Sources */, + B5D6F210250E1E3200DF5D2F /* Advanced.EvolutionDemo.V1.xcdatamodeld in Sources */, + B5D6F1FC250E0B1700DF5D2F /* Advanced.EvolutionDemo.V2.swift in Sources */, + B5D6F205250E0DD600DF5D2F /* Advanced.EvolutionDemo.V3.swift in Sources */, + B5D6F207250E0E3B00DF5D2F /* Advanced.EvolutionDemo.V4.swift in Sources */, B5A543E924FB84A1000DC5E3 /* Classic.ColorsDemo.DetailView.swift in Sources */, B5A543E724FB82BB000DC5E3 /* Classic.ColorsDemo.Filter.swift in Sources */, B5A543F324FB84EC000DC5E3 /* Classic.ColorsDemo.ItemCell.swift in Sources */, - B5D6F209250E14AA00DF5D2F /* Advanced.EvolutionDemo.Migrator.swift in Sources */, B5A543EF24FB84D1000DC5E3 /* Classic.ColorsDemo.LIstView.swift in Sources */, B5A543ED24FB84BE000DC5E3 /* Classic.ColorsDemo.MainView.swift in Sources */, B5A543DD24FB78F9000DC5E3 /* Classic.ColorsDemo.Palette.swift in Sources */, B5A3919824E7E67000E7E8BD /* Modern.ColorsDemo.Filter.swift in Sources */, - B5D6F1FC250E0B1700DF5D2F /* Advanced.EvolutionDemo.V2.swift in Sources */, B5A3919224E7E0C600E7E8BD /* Modern.ColorsDemo.Palette.swift in Sources */, B5A3919E24E8EEB600E7E8BD /* Modern.ColorsDemo.SwiftUI.swift in Sources */, B5A391A024E8F00A00E7E8BD /* Modern.ColorsDemo.UIKit.swift in Sources */, @@ -703,7 +736,6 @@ B5A3916524E698C700E7E8BD /* Modern.PlacemarksDemo.Place.swift in Sources */, B566C8EE24FA1EA3001134A1 /* Modern.PokedexDemo.Details.swift in Sources */, B566C8EC24F9D694001134A1 /* Modern.PokedexDemo.ItemCell.swift in Sources */, - B5D6F210250E1E3200DF5D2F /* Advanced.EvolutionDemo.V1.xcdatamodeld in Sources */, B566C8E824F9D406001134A1 /* Modern.PokedexDemo.ListView.swift in Sources */, B566C8EA24F9D412001134A1 /* Modern.PokedexDemo.ListViewController.swift in Sources */, B531EFED24EB7453005F247D /* Modern.PokedexDemo.MainView.swift in Sources */, @@ -712,7 +744,6 @@ B5A3918624E7A54A00E7E8BD /* Modern.TimeZonesDemo.TimeZone.swift in Sources */, B5A543EB24FB84AF000DC5E3 /* ⭐️Classic.ColorsDemo.DetailViewController.swift in Sources */, B5A543F124FB84DD000DC5E3 /* ⭐️Classic.ColorsDemo.ListViewController.swift in Sources */, - B5D6F205250E0DD600DF5D2F /* Advanced.EvolutionDemo.V3.swift in Sources */, B5A391A624E8F4EA00E7E8BD /* ⭐️Modern.ColorsDemo.MainView.swift in Sources */, B5A3916224E697BA00E7E8BD /* ⭐️Modern.PlacemarksDemo.MainView.swift in Sources */, B5A391B424E96C0A00E7E8BD /* ⭐️Modern.PokedexDemo.Form.swift in Sources */, @@ -721,6 +752,19 @@ B531EFEB24EB5ECD005F247D /* ⭐️Modern.PokedexDemo.Service.swift in Sources */, B5A391B924E96F8500E7E8BD /* ⭐️Modern.PokedexDemo.Species.swift in Sources */, B5A3918824E7A8F900E7E8BD /* ⭐️Modern.TimeZonesDemo.MainView.swift in Sources */, + B5A5440725049480000DC5E3 /* Advanced.EvolutionDemo.V1.Creature.swift in Sources */, + B5931B4225124756007DA58E /* Advanced.EvolutionDemo.V1.FromV2.swift in Sources */, + B54D2F7E25119DCE004BEC7D /* Advanced.EvolutionDemo.V1.FromV2.xcmappingmodel in Sources */, + B5A5440925049489000DC5E3 /* Advanced.EvolutionDemo.V2.Creature.swift in Sources */, + B5931B442512480A007DA58E /* Advanced.EvolutionDemo.V2.FromV1.swift in Sources */, + B54D2F7A25119540004BEC7D /* Advanced.EvolutionDemo.V2.FromV1.xcmappingmodel in Sources */, + B54D2F7C251196B6004BEC7D /* Advanced.EvolutionDemo.V2.FromV1MigrationPolicy.swift in Sources */, + B5931B4C251249EE007DA58E /* Advanced.EvolutionDemo.V2.FromV3.swift in Sources */, + B5A5440B25049492000DC5E3 /* Advanced.EvolutionDemo.V3.Creature.swift in Sources */, + B5931B46251248B0007DA58E /* Advanced.EvolutionDemo.V3.FromV2.swift in Sources */, + B5931B4A25124993007DA58E /* Advanced.EvolutionDemo.V3.FromV4.swift in Sources */, + B5A5440D2504949C000DC5E3 /* Advanced.EvolutionDemo.V4.Creature.swift in Sources */, + B5931B4825124940007DA58E /* Advanced.EvolutionDemo.V4.FromV3.swift in Sources */, B5A391AC24E9143B00E7E8BD /* Modern.ColorsDemo.UIKit.DetailView.swift in Sources */, B5A391AA24E9104300E7E8BD /* Modern.ColorsDemo.UIKit.ItemCell.swift in Sources */, B5A391A424E8F04300E7E8BD /* Modern.ColorsDemo.UIKit.ListView.swift in Sources */, @@ -749,12 +793,14 @@ B5A3911324E5424E00E7E8BD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + IPHONEOS_DEPLOYMENT_TARGET = 10.0; }; name = Debug; }; B5A3911424E5424E00E7E8BD /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + IPHONEOS_DEPLOYMENT_TARGET = 10.0; }; name = Release; }; diff --git a/Demo/⭐️Sources/Helpers/Menu/Menu.MainView.swift b/Demo/⭐️Sources/Helpers/Menu/Menu.MainView.swift index 5370d5f..5a69d16 100644 --- a/Demo/⭐️Sources/Helpers/Menu/Menu.MainView.swift +++ b/Demo/⭐️Sources/Helpers/Menu/Menu.MainView.swift @@ -96,9 +96,10 @@ extension Menu { Menu.ItemView( title: "Evolution", subtitle: "Migrating and reverse-migrating stores", - destination: { EmptyView() } + destination: { + Advanced.EvolutionDemo.MainView() + } ) - .disabled(true) Menu.ItemView( title: "Logger", subtitle: "Implementing a custom logger", diff --git a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.CreatureType.swift b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.CreatureType.swift index 5f5df1d..a8561e0 100644 --- a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.CreatureType.swift +++ b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.CreatureType.swift @@ -18,7 +18,13 @@ extension Advanced.EvolutionDemo { protocol Advanced_EvolutionDemo_CreatureType: DynamicObject, CustomStringConvertible { - var dnaCode: Int64 { get } + var dnaCode: Int64 { get set } + + static func dataSource(in dataStack: DataStack) -> Advanced.EvolutionDemo.CreaturesDataSource + + static func count(in transaction: BaseDataTransaction) throws -> Int + + static func create(in transaction: BaseDataTransaction) -> Self func mutate(in transaction: BaseDataTransaction) } diff --git a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.CreaturesDataSource.swift b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.CreaturesDataSource.swift new file mode 100644 index 0000000..127000c --- /dev/null +++ b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.CreaturesDataSource.swift @@ -0,0 +1,165 @@ +// +// Demo +// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved. + +import CoreStore +import Combine + + +// MARK: - Advanced.EvolutionDemo + +extension Advanced.EvolutionDemo { + + // MARK: - Advanced.EvolutionDemo.CreaturesDataSource + + final class CreaturesDataSource: ObservableObject { + + // MARK: Internal + + init( + listPublisher: ListPublisher, + dataStack: DataStack + ) { + + self.numberOfItems = { + listPublisher.snapshot.numberOfItems + } + self.itemDescriptionAtIndex = { index in + listPublisher.snapshot[index].object?.description + } + self.addItems = { count in + + dataStack.perform( + asynchronous: { transaction in + + let nextDNACode = try transaction.fetchCount(From()) + for offset in 0 ..< count { + + let object = transaction.create(Into()) + object.dnaCode = .init(nextDNACode + offset) + object.mutate(in: transaction) + } + }, + completion: { _ in } + ) + } + self.mutateItemAtIndex = { index in + + let object = listPublisher.snapshot[index] + dataStack.perform( + asynchronous: { transaction in + + object + .asEditable(in: transaction)? + .mutate(in: transaction) + }, + completion: { _ in } + ) + } + self.deleteAllItems = { + + dataStack.perform( + asynchronous: { transaction in + + try transaction.deleteAll(From()) + }, + completion: { _ in } + ) + } + listPublisher.addObserver(self) { [weak self] (listPublisher) in + + self?.objectWillChange.send() + } + } + + init( + listPublisher: ListPublisher, + dataStack: DataStack + ) { + + self.numberOfItems = { + listPublisher.snapshot.numberOfItems + } + self.itemDescriptionAtIndex = { index in + listPublisher.snapshot[index].object?.description + } + self.addItems = { count in + + dataStack.perform( + asynchronous: { transaction in + + let nextDNACode = try transaction.fetchCount(From()) + for offset in 0 ..< count { + + let object = transaction.create(Into()) + object.dnaCode = .init(nextDNACode + offset) + object.mutate(in: transaction) + } + }, + completion: { _ in } + ) + } + self.mutateItemAtIndex = { index in + + let object = listPublisher.snapshot[index] + dataStack.perform( + asynchronous: { transaction in + + object + .asEditable(in: transaction)? + .mutate(in: transaction) + }, + completion: { _ in } + ) + } + self.deleteAllItems = { + + dataStack.perform( + asynchronous: { transaction in + + try transaction.deleteAll(From()) + }, + completion: { _ in } + ) + } + listPublisher.addObserver(self) { [weak self] (listPublisher) in + + self?.objectWillChange.send() + } + } + + func numberOfCreatures() -> Int { + + return self.numberOfItems() + } + + func creatureDescription(at index: Int) -> String? { + + return self.itemDescriptionAtIndex(index) + } + + func mutate(at index: Int) { + + self.mutateItemAtIndex(index) + } + + func add(count: Int) { + + self.addItems(count) + } + + func clear() { + + self.deleteAllItems() + } + + + // MARK: Private + + private let numberOfItems: () -> Int + private let itemDescriptionAtIndex: (Int) -> String? + private let mutateItemAtIndex: (Int) -> Void + private let addItems: (Int) -> Void + private let deleteAllItems: () -> Void + } +} diff --git a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.GeologicalPeriod.swift b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.GeologicalPeriod.swift index afd50db..c96ae16 100644 --- a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.GeologicalPeriod.swift +++ b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.GeologicalPeriod.swift @@ -2,13 +2,17 @@ // Demo // Copyright © 2020 John Rommel Estropia, Inc. All rights reserved. +import CoreStore + + // MARK: - AdvancedEvolutionDemo extension Advanced.EvolutionDemo { // MARK: - GeologicalPeriod - enum GeologicalPeriod: CaseIterable { + enum GeologicalPeriod: RawRepresentable, CaseIterable, Hashable, CustomStringConvertible { + // MARK: Internal @@ -17,6 +21,11 @@ extension Advanced.EvolutionDemo { case ageOfReptiles case ageOfMammals + var version: ModelVersion { + + return self.rawValue + } + var creatureType: Advanced.EvolutionDemo.CreatureType.Type { switch self { @@ -31,5 +40,60 @@ extension Advanced.EvolutionDemo { return Advanced.EvolutionDemo.V4.Creature.self } } + + + // MARK: CustomStringConvertible + + var description: String { + + switch self { + + case .ageOfInvertebrates: + return "Invertebrates" + case .ageOfFishes: + return "Fishes" + case .ageOfReptiles: + return "Reptiles" + case .ageOfMammals: + return "Mammals" + } + } + + + // MARK: RawRepresentable + + typealias RawValue = ModelVersion + + var rawValue: ModelVersion { + + switch self { + + case .ageOfInvertebrates: + return Advanced.EvolutionDemo.V1.name + case .ageOfFishes: + return Advanced.EvolutionDemo.V2.name + case .ageOfReptiles: + return Advanced.EvolutionDemo.V3.name + case .ageOfMammals: + return Advanced.EvolutionDemo.V4.name + } + } + + init?(rawValue: ModelVersion) { + + switch rawValue { + + case Advanced.EvolutionDemo.V1.name: + self = .ageOfInvertebrates + case Advanced.EvolutionDemo.V2.name: + self = .ageOfFishes + case Advanced.EvolutionDemo.V3.name: + self = .ageOfReptiles + case Advanced.EvolutionDemo.V4.name: + self = .ageOfMammals + default: + return nil + } + } } } diff --git a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.ItemView.swift b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.ItemView.swift index 77901f8..402eb06 100644 --- a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.ItemView.swift +++ b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.ItemView.swift @@ -2,4 +2,74 @@ // Demo // Copyright © 2020 John Rommel Estropia, Inc. All rights reserved. -import Foundation +import SwiftUI + +// MARK: - Advanced.EvolutionDemo + +extension Advanced.EvolutionDemo { + + // MARK: - Advanced.EvolutionDemo.ItemView + + struct ItemView: View { + + // MARK: Internal + + init(description: String?, mutate: @escaping () -> Void) { + + self.description = description + self.mutate = mutate + } + + + // MARK: View + + var body: some View { + HStack { + Text(self.description ?? "") + .font(.footnote) + .foregroundColor(.primary) + Spacer() + Button( + action: self.mutate, + label: { + Text("Mutate") + .foregroundColor(.accentColor) + .fontWeight(.bold) + } + ) + .buttonStyle(PlainButtonStyle()) + } + .disabled(self.description == nil) + } + + + // MARK: FilePrivate + + fileprivate let description: String? + fileprivate let mutate: () -> Void + } +} + +#if DEBUG + +struct _Demo_Advanced_EvolutionDemo_ItemView_Preview: PreviewProvider { + + // MARK: PreviewProvider + + static var previews: some View { + Advanced.EvolutionDemo.ItemView( + description: """ + dnaCode: 123 + numberOfLimbs: 4 + hasVertebrae: true + hasHead: true + hasTail: true + habitat: land + hasWings: false + """, + mutate: {} + ) + } +} + +#endif diff --git a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.ListView.swift b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.ListView.swift index 77901f8..ce3700b 100644 --- a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.ListView.swift +++ b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.ListView.swift @@ -2,4 +2,98 @@ // Demo // Copyright © 2020 John Rommel Estropia, Inc. All rights reserved. -import Foundation +import CoreStore +import SwiftUI + +// MARK: - Advanced.EvolutionDemo + +extension Advanced.EvolutionDemo { + + // MARK: - Advanced.EvolutionDemo.ListView + + struct ListView: View { + + // MARK: View + + var body: some View { + let dataSource = self.dataSource + return List { + ForEach(0 ..< dataSource.numberOfCreatures(), id: \.self) { (index) in + Advanced.EvolutionDemo.ItemView( + description: dataSource.creatureDescription(at: index), + mutate: { + + dataSource.mutate(at: index) + } + ) + } + } + .listStyle(PlainListStyle()) + } + + + // MARK: Internal + + init( + period: Advanced.EvolutionDemo.GeologicalPeriod, + dataStack: DataStack, + dataSource: Advanced.EvolutionDemo.CreaturesDataSource + ) { + + self.period = period + self.dataStack = dataStack + self.dataSource = dataSource + } + + + // MARK: Private + + private let period: Advanced.EvolutionDemo.GeologicalPeriod + + private let dataStack: DataStack + + @ObservedObject + private var dataSource: Advanced.EvolutionDemo.CreaturesDataSource + } +} + + +#if DEBUG + +struct _Demo_Advanced_EvolutionDemo_ListView_Preview: PreviewProvider { + + // MARK: PreviewProvider + + static var previews: some View { + + let dataStack = DataStack( + CoreStoreSchema( + modelVersion: Advanced.EvolutionDemo.V4.name, + entities: [ + Entity("Creature") + ] + ) + ) + try! dataStack.addStorageAndWait( + SQLiteStore(fileName: "Advanced.EvolutionDemo.ListView.Preview.sqlite") + ) + try! dataStack.perform( + synchronous: { transaction in + + for dnaCode in 0 ..< 10 as Range { + + let object = transaction.create(Into()) + object.dnaCode = dnaCode + object.mutate(in: transaction) + } + } + ) + return Advanced.EvolutionDemo.ListView( + period: .ageOfMammals, + dataStack: dataStack, + dataSource: Advanced.EvolutionDemo.V4.Creature.dataSource(in: dataStack) + ) + } +} + +#endif diff --git a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.MainView.swift b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.MainView.swift index 77901f8..072995a 100644 --- a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.MainView.swift +++ b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.MainView.swift @@ -2,4 +2,77 @@ // Demo // Copyright © 2020 John Rommel Estropia, Inc. All rights reserved. -import Foundation +import CoreStore +import SwiftUI + +// MARK: - Advanced.EvolutionDemo + +extension Advanced.EvolutionDemo { + + // MARK: - Advanced.EvolutionDemo.MainView + + struct MainView: View { + + // MARK: View + + var body: some View { + let migrator = self.migrator + let listView: AnyView + if let current = migrator.current { + + listView = AnyView( + Advanced.EvolutionDemo.ListView( + period: current.period, + dataStack: current.dataStack, + dataSource: current.dataSource + ) + ) + } + else { + + listView = AnyView( + Advanced.EvolutionDemo.ProgressView(progress: migrator.progress) + ) + } + + return VStack(spacing: 0) { + HStack(alignment: .center, spacing: 0) { + Text("Age of") + .padding(.trailing) + Picker(selection: self.$migrator.currentPeriod, label: EmptyView()) { + ForEach(Advanced.EvolutionDemo.GeologicalPeriod.allCases, id: \.self) { period in + Text(period.description).tag(period) + } + } + .pickerStyle(SegmentedPickerStyle()) + } + .padding() + listView + .edgesIgnoringSafeArea(.vertical) + } + .navigationBarTitle("Evolution") + .disabled(migrator.isBusy || migrator.current == nil) + } + + + // MARK: Private + + @ObservedObject + private var migrator: Advanced.EvolutionDemo.Migrator = .init() + } +} + + +#if DEBUG + +struct _Demo_Advanced_EvolutionDemo_MainView_Preview: PreviewProvider { + + // MARK: PreviewProvider + + static var previews: some View { + + Advanced.EvolutionDemo.MainView() + } +} + +#endif diff --git a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.Migrator.swift b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.Migrator.swift index bef1d86..b0b21b0 100644 --- a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.Migrator.swift +++ b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.Migrator.swift @@ -14,34 +14,20 @@ extension Advanced.EvolutionDemo { // MARK: - Advanced.EvolutionDemo.Migrator final class Migrator: ObservableObject { - - var currentPeriod: Advanced.EvolutionDemo.GeologicalPeriod? { - - return self.current?.period - } - - - // MARK: Private - - private var current: (period: Advanced.EvolutionDemo.GeologicalPeriod, dataStack: DataStack)? { - - willSet { - - self.objectWillChange.send() - } - } - - private func findAndSetCurrentVersion() { - + + /** + ⭐️ Sample 1: Creating a complex `DataStack` that contains all schema histories. The `exactCurrentModelVersion` will specify the target version (if required), and `migrationChain` will provide the upgrade/downgrade progressive migration path. + */ + private func createDataStack( + exactCurrentModelVersion: ModelVersion?, + migrationChain: MigrationChain + ) -> DataStack { + let xcodeV1ToV2ModelSchema = XcodeDataModelSchema.from( modelName: "Advanced.EvolutionDemo.V1", - bundle: Bundle(for: Advanced.EvolutionDemo.V1.Creature.self), - migrationChain: [ - Advanced.EvolutionDemo.V1.name, - Advanced.EvolutionDemo.V2.name - ] + bundle: Bundle(for: Advanced.EvolutionDemo.V1.Creature.self) ) - let dataStack = DataStack( + return DataStack( schemaHistory: SchemaHistory( allSchema: xcodeV1ToV2ModelSchema.allSchema + [ @@ -58,26 +44,196 @@ extension Advanced.EvolutionDemo { ] ) ], - migrationChain: [ - Advanced.EvolutionDemo.V1.name, - Advanced.EvolutionDemo.V2.name, - Advanced.EvolutionDemo.V3.name, - Advanced.EvolutionDemo.V4.name - ] + migrationChain: migrationChain, + exactCurrentModelVersion: exactCurrentModelVersion ) ) } + + /** + ⭐️ Sample 2: Creating a complex `SQLiteStore` that contains all schema mappings for both upgrade and downgrade cases. + */ + private func accessSQLiteStore() -> SQLiteStore { + + let upgradeMappings: [SchemaMappingProvider] = [ + Advanced.EvolutionDemo.V2.FromV1.mapping, + Advanced.EvolutionDemo.V3.FromV2.mapping, + Advanced.EvolutionDemo.V4.FromV3.mapping + ] + let downgradeMappings: [SchemaMappingProvider] = [ + Advanced.EvolutionDemo.V3.FromV4.mapping, + Advanced.EvolutionDemo.V2.FromV3.mapping, + Advanced.EvolutionDemo.V1.FromV2.mapping, + ] + return SQLiteStore( + fileName: "Advanced.EvolutionDemo.sqlite", + configuration: nil, + migrationMappingProviders: upgradeMappings + downgradeMappings, + localStorageOptions: [] + ) + } + + + // MARK: Internal + + var currentPeriod: Advanced.EvolutionDemo.GeologicalPeriod = Advanced.EvolutionDemo.GeologicalPeriod.allCases.last! { + + didSet { + + self.selectModelVersion(self.currentPeriod) + } + } + + private(set) var current: ( + period: Advanced.EvolutionDemo.GeologicalPeriod, + dataStack: DataStack, + dataSource: Advanced.EvolutionDemo.CreaturesDataSource + )? { + + willSet { + + self.objectWillChange.send() + } + } + + private(set) var isBusy: Bool = false + + private(set) var progress: Progress? + + + init() { + + self.synchronizeCurrentVersion() + } - private func selectModelVersion(_ period: GeologicalPeriod) { - - guard period != self.current?.period else { + + // MARK: Private + + private func synchronizeCurrentVersion() { + + // Since we are only interested in finding current version, we'll assume an upgrading `MigrationChain` + let dataStack = self.createDataStack( + exactCurrentModelVersion: nil, + migrationChain: MigrationChain( + Advanced.EvolutionDemo.GeologicalPeriod.allCases.map({ $0.version }) + ) + ) + let migrations = try! dataStack.requiredMigrationsForStorage( + self.accessSQLiteStore() + ) + if let period = migrations.first + .flatMap({ Advanced.EvolutionDemo.GeologicalPeriod(rawValue: $0.sourceVersion) }) { + + self.selectModelVersion(period) + } + else { + + self.selectModelVersion(self.currentPeriod) + } + } + + private func selectModelVersion(_ period: Advanced.EvolutionDemo.GeologicalPeriod) { + + let currentPeriod = self.current?.period + guard period != currentPeriod else { return } + + self.objectWillChange.send() + + self.isBusy = true // explicitly trigger `NSPersistentStore` cleanup by deallocating the `DataStack` self.current = nil - + + let migrationChain: MigrationChain + switch (currentPeriod?.version, period.version) { + + case (nil, let newVersion): + migrationChain = [newVersion] + + case (let currentVersion?, let newVersion): + let upgradeMigrationChain = Advanced.EvolutionDemo.GeologicalPeriod.allCases + .map({ $0.version }) + let currentVersionIndex = upgradeMigrationChain.firstIndex(of: currentVersion)! + let newVersionIndex = upgradeMigrationChain.firstIndex(of: newVersion)! + + migrationChain = MigrationChain( + currentVersionIndex > newVersionIndex + ? upgradeMigrationChain.reversed() + : upgradeMigrationChain + ) + } + let dataStack = self.createDataStack( + exactCurrentModelVersion: period.version, + migrationChain: migrationChain + ) + + let completion = { [weak self] () -> Void in + + guard let self = self else { + + return + } + self.objectWillChange.send() + defer { + + self.isBusy = false + } + self.current = ( + period: period, + dataStack: dataStack, + dataSource: period.creatureType.dataSource(in: dataStack) + ) + self.currentPeriod = period + } + + self.progress = dataStack.addStorage( + self.accessSQLiteStore(), + completion: { [weak self] result in + + guard let self = self else { + + return + } + guard case .success = result else { + + self.objectWillChange.send() + self.isBusy = false + return + } + if self.progress == nil { + + self.spawnCreatures(in: dataStack, period: period, completion: completion) + } + else { + + completion() + } + } + ) + } + + private func spawnCreatures( + in dataStack: DataStack, + period: Advanced.EvolutionDemo.GeologicalPeriod, + completion: @escaping () -> Void + ) { + + dataStack.perform( + asynchronous: { (transaction) in + + let creatureType = period.creatureType + for dnaCode in try creatureType.count(in: transaction) ..< 10000 { + + let object = creatureType.create(in: transaction) + object.dnaCode = Int64(dnaCode) + object.mutate(in: transaction) + } + }, + completion: { _ in completion() } + ) } diff --git a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.ProgressView.swift b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.ProgressView.swift new file mode 100644 index 0000000..4f3744b --- /dev/null +++ b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.ProgressView.swift @@ -0,0 +1,127 @@ +// +// Demo +// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved. + +import SwiftUI + +// MARK: - Advanced.EvolutionDemo + +extension Advanced.EvolutionDemo { + + // MARK: - Advanced.EvolutionDemo.ProgressView + + struct ProgressView: View { + + // MARK: Internal + + init(progress: Progress?) { + + self.progressObserver = .init(progress) + } + + + // MARK: View + + var body: some View { + + guard self.progressObserver.isMigrating else { + + return AnyView( + VStack(alignment: .center) { + Text("Preparing creatures...") + .padding() + Spacer() + } + .padding() + ) + } + return AnyView( + VStack(alignment: .leading) { + Text("Migrating: \(self.progressObserver.localizedDescription)") + .font(.headline) + .padding([.top, .horizontal]) + Text("Progressive step: \(self.progressObserver.localizedAdditionalDescription)") + .font(.subheadline) + .padding(.horizontal) + GeometryReader { geometry in + ZStack(alignment: .leading) { + Color.gray + .opacity(0.2) + .frame(width: geometry.size.width, height: 8) + .cornerRadius(4.0) + Color.blue + .frame( + width: geometry.size.width + * self.progressObserver.fractionCompleted, + height: 8 + ) + .cornerRadius(4.0) + } + } + .fixedSize(horizontal: false, vertical: true) + .padding() + Spacer() + } + .padding() + ) + } + + + // MARK: FilePrivate + + @ObservedObject + private var progressObserver: ProgressObserver + + + // MARK: - ProgressObserver + + fileprivate final class ProgressObserver: ObservableObject { + + private(set) var fractionCompleted: CGFloat = 0 + private(set) var localizedDescription: String = "" + private(set) var localizedAdditionalDescription: String = "" + + var isMigrating: Bool { + + return self.progress != nil + } + + init(_ progress: Progress?) { + + self.progress = progress + + progress?.setProgressHandler { [weak self] (progess) in + + guard let self = self else { + return + } + self.objectWillChange.send() + self.fractionCompleted = CGFloat(progress?.fractionCompleted ?? 0) + self.localizedDescription = progress?.localizedDescription ?? "" + self.localizedAdditionalDescription = progress?.localizedAdditionalDescription ?? "" + } + } + + // MARK: Private + + private let progress: Progress? + } + } +} + +#if DEBUG + +struct _Demo_Advanced_EvolutionDemo_ProgressView_Preview: PreviewProvider { + + // MARK: PreviewProvider + + static var previews: some View { + let progress = Progress(totalUnitCount: 10) + progress.completedUnitCount = 3 + return Advanced.EvolutionDemo.ProgressView( + progress: progress + ) + } +} + +#endif diff --git a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V1.Creature.swift b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V1.Creature.swift index 57048b0..36e940f 100644 --- a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V1.Creature.swift +++ b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V1.Creature.swift @@ -30,6 +30,31 @@ final class Advanced_EvolutionDemo_V1_Creature: NSManagedObject, Advanced.Evolut // MARK: Advanced.EvolutionDemo.CreatureType + + static func dataSource(in dataStack: DataStack) -> Advanced.EvolutionDemo.CreaturesDataSource { + + return .init( + listPublisher: dataStack.publishList( + From() + .orderBy(.descending(\.dnaCode)) + ), + dataStack: dataStack + ) + } + + static func count(in transaction: BaseDataTransaction) throws -> Int { + + return try transaction.fetchCount( + From() + ) + } + + static func create(in transaction: BaseDataTransaction) -> Advanced.EvolutionDemo.V1.Creature { + + return transaction.create( + Into() + ) + } func mutate(in transaction: BaseDataTransaction) { diff --git a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V1.FromV2.swift b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V1.FromV2.swift new file mode 100644 index 0000000..d50df84 --- /dev/null +++ b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V1.FromV2.swift @@ -0,0 +1,27 @@ +// +// Demo +// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved. + +import CoreStore + + +// MARK: - Advanced.EvolutionDemo.V1 + +extension Advanced.EvolutionDemo.V1 { + + // MARK: - Advanced.EvolutionDemo.V1.FromV2 + + enum FromV2 { + + // MARK: Internal + + static var mapping: XcodeSchemaMappingProvider { + + return XcodeSchemaMappingProvider( + from: Advanced.EvolutionDemo.V2.name, + to: Advanced.EvolutionDemo.V1.name, + mappingModelBundle: Bundle(for: Advanced.EvolutionDemo.V1.Creature.self) + ) + } + } +} diff --git a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V1.FromV2.xcmappingmodel/xcmapping.xml b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V1.FromV2.xcmappingmodel/xcmapping.xml new file mode 100644 index 0000000..5589b46 --- /dev/null +++ b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V1.FromV2.xcmappingmodel/xcmapping.xml @@ -0,0 +1,81 @@ + + + + + + 134481920 + F17B8B92-EEB0-4A30-98EC-425208280CBC + 105 + + + + NSPersistenceFrameworkVersion + 977 + NSStoreModelVersionHashes + + XDDevAttributeMapping + + 0plcXXRN7XHKl5CcF+fwriFmUpON3ZtcI/AfK748aWc= + + XDDevEntityMapping + + qeN1Ym3TkWN1G6dU9RfX6Kd2ccEvcDVWHpd3LpLgboI= + + XDDevMappingModel + + EqtMzvRnVZWkXwBHu4VeVGy8UyoOe+bi67KC79kphlQ= + + XDDevPropertyMapping + + XN33V44TTGY4JETlMoOB5yyTKxB+u4slvDIinv0rtGA= + + XDDevRelationshipMapping + + akYY9LhehVA/mCb4ATLWuI9XGLcjpm14wWL1oEBtIcs= + + + NSStoreModelVersionHashesDigest + +Hmc2uYZK6og+Pvx5GUJ7oW75UG4V/ksQanTjfTKUnxyGWJRMtB5tIRgVwGsrd7lz/QR57++wbvWsr6nxwyS0A== + NSStoreModelVersionHashesVersion + 3 + NSStoreModelVersionIdentifiers + + + + + + + + + dnaCode + + + + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMSAAGGoF8Q +D05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGsCwwXGB0eJiswMTQ4VSRudWxs1Q0ODxAREhMUFRZZTlNPcGVyYW5kXk5TU2VsZWN0b3JOYW1lXxAQTlNFeHByZXNzaW9uVHlwZVtOU0FyZ3VtZW50c1YkY2xhc3OAA4ACEASABoALXxAQdmFsdWVGb3JLZXlQYXRoOtMZDxEaGxxaTlNWYXJpYWJsZYAEEAKABVZzb3VyY2XSHyAhIlokY2xhc3NuYW1lWCRjbGFzc2VzXxAUTlNWYXJpYWJsZUV4cHJlc3Npb26jIyQlXxAUTlNWYXJpYWJsZUV4cHJlc3Npb25cTlNFeHByZXNzaW9uWE5TT2JqZWN00icRKCpaTlMub2JqZWN0c6EpgAeACtMRDywtLi9ZTlNLZXlQYXRogAkQCoAIXxAQbnVtYmVyT2ZGbGlwcGVyc9IfIDIzXxAcTlNLZXlQYXRoU3BlY2lmaWVyRXhwcmVzc2lvbqMyJCXSHyA1Nl5OU011dGFibGVBcnJheaM1NyVXTlNBcnJhedIfIDk6XxATTlNLZXlQYXRoRXhwcmVzc2lvbqQ5OyQlXxAUTlNGdW5jdGlvbkV4cHJlc3Npb24ACAARABoAJAApADIANwBJAEwAUQBTAGAAZgBxAHsAigCdAKkAsACyALQAtgC4ALoAzQDUAN8A4QDjAOUA7ADxAPwBBQEcASABNwFEAU0BUgFdAV8BYQFjAWoBdAF2AXgBegGNAZIBsQG1AboByQHNAdUB2gHwAfUAAAAAAAACAQAAAAAAAAA8AAAAAAAAAAAAAAAAAAACDA== + + numberOfFlagella + + + + Creature + Undefined + 1 + Creature + 1 + + + + + + ⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V1.xcdatamodeld/Advanced.EvolutionDemo.V2.xcdatamodel + YnBsaXN0MDDUAAEAAgADAAQABQAGAAcAClgkdmVyc2lvblkkYXJjaGl2ZXJUJHRvcFgkb2JqZWN0 +cxIAAYagXxAPTlNLZXllZEFyY2hpdmVy0QAIAAlUcm9vdIABrxDJAAsADAAbADcAOAA5AEEAQgBdAF4AXwBlAGYAcgCIAIkAigCLAIwAjQCOAI8AkACRAKoArQC0ALoAyQDYANsA6gD5APwAXAEMARsBHwEjATIBOAE5AUEBUAFRAVoBaAFpAWoBawFsAW0BggGDAYsBjAGNAZkBrQGuAa8BsAGxAbIBswG0AbUBxAHTAeIB5gH1AgQCEwIiAjECPQJPAlACUQJSAlMCVAJVAlYCZQJmAnUChAKTApQCowKyAsECyQLeAt8C5wLzAwcDFgMlAzQDOANHA1YDZQN0A4MDjwOhA7ADvwPOA90D7AP7BAoEHwQgBCgENARIBFcEZgR1BHkEiASXBKYEtQTEBNAE4gTxBPIFAQUQBR8FIAUvBT4FTQViBWMFawV3BYsFmgWpBbgFvAXLBdoF6QX4BgcGEwYlBjQGNQZEBlMGYgZjBnIGgQaQBqUGpgauBroGzgbdBuwG+wb/Bw4HHQcsBzsHSgdWB2gHdweGB5UHpAezB8IH0QfSB9UH3gfiB+YH6gfyB/UH+Qf6VSRudWxs1wANAA4ADwAQABEAEgATABQAFQAWABcAGAAXABpfEA9feGRfcm9vdFBhY2thZ2VWJGNsYXNzXF94ZF9jb21tZW50c18QEF94ZF9tb2RlbE1hbmFnZXJfEBVfY29uZmlndXJhdGlvbnNCeU5hbWVdX3hkX21vZGVsTmFtZV8QF19tb2RlbFZlcnNpb25JZGVudGlmaWVygAKAyIDFgACAxoAAgMfeABwAHQAeAB8AIAAhACIADgAjACQAJQAmACcAKAApACoAKwAJACkAFwAvADAAMQAyADMAKQApABdfEBxYREJ1Y2tldEZvckNsYXNzZXN3YXNFbmNvZGVkXxAaWERCdWNrZXRGb3JQYWNrYWdlc3N0b3JhZ2VfEBxYREJ1Y2tldEZvckludGVyZmFjZXNzdG9yYWdlXxAPX3hkX293bmluZ01vZGVsXxAdWERCdWNrZXRGb3JQYWNrYWdlc3dhc0VuY29kZWRWX293bmVyXxAbWERCdWNrZXRGb3JEYXRhVHlwZXNzdG9yYWdlW192aXNpYmlsaXR5XxAZWERCdWNrZXRGb3JDbGFzc2Vzc3RvcmFnZVVfbmFtZV8QH1hEQnVja2V0Rm9ySW50ZXJmYWNlc3dhc0VuY29kZWRfEB5YREJ1Y2tldEZvckRhdGFUeXBlc3dhc0VuY29kZWRfEBBfdW5pcXVlRWxlbWVudElEgASAw4DBgAGABIAAgMKAxBAAgAWAA4AEgASAAFBTWUVT0wA6ADsADgA8AD4AQFdOUy5rZXlzWk5TLm9iamVjdHOhAD2ABqEAP4AHgCVYQ3JlYXR1cmXfEBAAQwBEAEUARgAhAEcASAAjAEkASgAOACUASwBMACgATQBOAE8AKQApABQAUwBUADEAKQBOAFcAPQBOAFoAWwBcXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zZHVwbGljYXRlc18QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNzdG9yYWdlW19pc0Fic3RyYWN0gAmALYAEgASAAoAKgL6ABIAJgMCABoAJgL+ACAgSr8lB/VdvcmRlcmVk0wA6ADsADgBgAGIAQKEAYYALoQBjgAyAJV5YRF9QU3RlcmVvdHlwZdkAIQAlAGcADgAoAGgAIwBNAGkAPwBhAE4AbQAXACkAMQBcAHFfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAB4ALgAmALIAAgAQIgA3TADoAOwAOAHMAfQBAqQB0AHUAdgB3AHgAeQB6AHsAfIAOgA+AEIARgBKAE4AUgBWAFqk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lAWIBYwFkAWUBZoAzgF6AdYCOgKeAJVxoYXNWZXJ0ZWJyYWVXaGFzVGFpbFdkbmFDb2RlXxAQbnVtYmVyT2ZGbGlwcGVyc1doYXNIZWFk3xASAJIAkwCUAW4AIQCWAJcBbwAjAJUBcACYAA4AJQCZAJoAKACbABcAFwAXACkAPwBcAFwBeAAxAFwATgBcAXwBXABcAFwBgABcXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASABwgIgDUIgAkIgF2ALggIgDQIEwAAAAELqNjo0wA6ADsADgGEAYcAQKIBhQGGgDaAN6IBiAGJgDiAS4AlXxASWERfUFByb3BTdGVyZW90eXBlXxASWERfUEF0dF9TdGVyZW90eXBl2QAhACUBjgAOACgBjwAjAE0BkAFiAYUATgBtABcAKQAxAFwBmF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYAzgDaACYAsgACABAiAOdMAOgA7AA4BmgGjAECoAZsBnAGdAZ4BnwGgAaEBooA6gDuAPIA9gD6AP4BAgEGoAaQBpQGmAacBqAGpAaoBq4BCgEOARIBGgEeASIBJgEqAJV8QG1hEX1BQU0tfaXNTdG9yZWRJblRydXRoRmlsZV8QG1hEX1BQU0tfdmVyc2lvbkhhc2hNb2RpZmllcl8QEFhEX1BQU0tfdXNlckluZm9fEBFYRF9QUFNLX2lzSW5kZXhlZF8QElhEX1BQU0tfaXNPcHRpb25hbF8QGlhEX1BQU0tfaXNTcG90bGlnaHRJbmRleGVkXxARWERfUFBTS19lbGVtZW50SURfEBNYRF9QUFNLX2lzVHJhbnNpZW503xAPAJIAkwCUACEAlQCWAJcAIwCYAA4AJQCZAJoAKACbABcA/gAXAYgAXABcAFwAMQBcAKQBmwBcAFwAFwBcgACAIoAAgDgICAgIgBqAOggIgAAI3xAPAJIAkwCUACEAlQCWAJc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tGm8acRqCGoQahhqIGooajBqOGpAakhqUGtMa1RrXGtka2xrcGt0a3hrfGuEa4xrkGuUa5xroGycbKRsrGy0bLxswGzEbMhszGzUbNxs4GzkbOxs8G3sbfRt/G4EbgxuEG4UbhhuHG4kbixuMG40bjxuQG50bnhufG6Eb4BviG+Qb5hvoG+kb6hvrG+wb7hvwG/Eb8hv0G/UcNBw2HDgcOhw8HD0cPhw/HEAcQhxEHEUcRhxIHEkciByKHIwcjhyQHJEckhyTHJQclhyYHJkcmhycHJ0c3BzeHOAc4hzkHOUc5hznHOgc6hzsHO0c7hzwHPEdMB0yHTQdNh04HTkdOh07HTwdPh1AHUEdQh1EHUUdah2OHbUd2R3bHd0d3x3hHeMd5R3mHegd9R4EHgYeCB4KHgweDh4QHhIeIR4jHiUeJx4pHiseLR4vHjEecB5yHnQedh54Hnkeeh57Hnwefh6AHoEegh6EHoUexB7GHsgeyh7MHs0ezh7PHtAe0h7UHtUe1h7YHtkfGB8aHxwfHh8gHyEfIh8jHyQfJh8oHykfKh8sHy0fbB9uH3Afch90H3Ufdh93H3gfeh98H30ffh+AH4EfwB/CH8Qfxh/IH8kfyh/LH8wfzh/QH9Ef0h/UH9UgFCAWIBggGiAcIB0gHiAfICAgIiAkICUgJiAoICkgaCBqIGwgbiBwIHEgciBzIHQgdiB4IHkgeiB8IH0gyCDrIQshKyEtIS8hMSEzITUhNiE3ITkhOiE8IT0hPyFBIUIhQyFFIUYhSyFYIV0hXyFhIWYhaCFqIWwhkSG1IdwiACICIgQiBiIIIgoiDCINIg8iHCItIi8iMSIzIjUiNyI5IjsiPSJOIlAiUiJUIlYiWCJaIlwiXiJgIp8ioSKjIqUipyKoIqkiqiKrIq0iryKwIrEisyK0IvMi9SL3Ivki+yL8Iv0i/iL/IwEjAyMEIwUjByMII0cjSSNLI00jTyNQI1EjUiNTI1UjVyNYI1kjWyNcI2kjaiNrI20jrCOuI7AjsiO0I7UjtiO3I7gjuiO8I70jviPAI8EkACQCJAQkBiQIJAkkCiQLJAwkDiQQJBEkEiQUJBUkVCRWJFgkWiRcJF0kXiRfJGAkYiRkJGUkZiRoJGkkqCSqJKwkriSwJLEksiSzJLQktiS4JLkkuiS8JL0k/CT+JQAlAiUEJQUlBiU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 + + ⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V1.xcdatamodeld/Advanced.EvolutionDemo.V1.xcdatamodel + YnBsaXN0MDDUAAEAAgADAAQABQAGAAcAClgkdmVyc2lvblkkYXJjaGl2ZXJUJHRvcFgkb2JqZWN0 +cxIAAYagXxAPTlNLZXllZEFyY2hpdmVy0QAIAAlUcm9vdIABrxB/AAsADAAbADcAOAA5AEEAQgBdAF4AXwBlAGYAcgCIAIkAigCLAIwAjQCOAI8AkACRAKoArQC0ALoAyQDYANsA6gD5APwAXAEMARsBHwEjATIBOAE5AUEBUAFRAVoBYgFjAWQBeQF6AYIBgwGEAZABpAGlAaYBpwGoAakBqgGrAawBuwHKAdkB3QHsAfsCCgIZAigCNAJGAkcCSAJJAkoCSwJMAk0CXAJdAmwCewKKAosCmgKpArgCwALVAtYC3gLqAv4DDQMcAysDLwM+A00DXANrA3oDhgOYA6cDqAO3A8YD1QPWA+UD9AQDBAQEBwQQBBQEGAQcBCQEJwQrBCxVJG51bGzXAA0ADgAPABAAEQASABMAFAAVABYAFwAYABcAGl8QD194ZF9yb290UGFja2FnZVYkY2xhc3NcX3hkX2NvbW1lbnRzXxAQX3hkX21vZGVsTWFuYWdlcl8QFV9jb25maWd1cmF0aW9uc0J5TmFtZV1feGRfbW9kZWxOYW1lXxAXX21vZGVsVmVyc2lvbklkZW50aWZpZXKAAoB+gHuAAIB8gACAfd4AHAAdAB4AHwAgACEAIgAOACMAJAAlACYAJwAoACkAKgArAAkAKQAXAC8AMAAxADIAMwApACkAF18QHFhEQnVja2V0Rm9yQ2xhc3Nlc3dhc0VuY29kZWRfEBpYREJ1Y2tldEZvclBhY2thZ2Vzc3RvcmFnZV8QHFhEQnVja2V0Rm9ySW50ZXJmYWNlc3N0b3JhZ2VfEA9feGRfb3duaW5nTW9kZWxfEB1YREJ1Y2tldEZvclBhY2thZ2Vzd2FzRW5jb2RlZFZfb3duZXJfEBtYREJ1Y2tldEZvckRhdGFUeXBlc3N0b3JhZ2VbX3Zpc2liaWxpdHlfEBlYREJ1Y2tldEZvckNsYXNzZXNzdG9yYWdlVV9uYW1lXxAfWERCdWNrZXRGb3JJbnRlcmZhY2Vzd2FzRW5jb2RlZF8QHlhEQnVja2V0Rm9yRGF0YVR5cGVzd2FzRW5jb2RlZF8QEF91bmlxdWVFbGVtZW50SUSABIB5gHeAAYAEgACAeIB6EACABYADgASABIAAUFNZRVPTADoAOwAOADwAPgBAV05TLmtleXNaTlMub2JqZWN0c6EAPYAGoQA/gAeAJVhDcmVhdHVyZd8QEABDAEQARQBGACEARwBIACMASQBKAA4AJQBLAEwAKABNAE4ATwApACkAFABTAFQAMQApAE4AVwA9AE4AWgBbAFxfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2VfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNkdXBsaWNhdGVzXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3N0b3JhZ2VbX2lzQWJzdHJhY3SACYAtgASABIACgAqAdIAEgAmAdoAGgAmAdYAICBK59ulAV29yZGVyZWTTADoAOwAOAGAAYgBAoQBhgAuhAGOADIAlXlhEX1BTdGVyZW90eXBl2QAhACUAZwAOACgAaAAjAE0AaQA/AGEATgBtABcAKQAxAFwAcV8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzb3JkZXJlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QIVhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzc3RvcmFnZYAHgAuACYAsgACABAiADdMAOgA7AA4AcwB9AECpAHQAdQB2AHcAeAB5AHoAewB8gA6AD4AQgBGAEoATgBSAFYAWqQB+AH8AgACBAIIAgwCEAIUAhoAXgBuAHIAegB+AIYAjgCaAKoAlXxATWERQTUNvbXBvdW5kSW5kZXhlc18QEFhEX1BTS19lbGVtZW50SURfEBlYRFBNVW5pcXVlbmVzc0NvbnN0cmFpbnRzXxAaWERfUFNLX3ZlcnNpb25IYXNoTW9kaWZpZXJfEBlYRF9QU0tfZmV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bGJ0YnhigGKIYoxikGKYYpxisGLkYvhjAGMIYxxjJGMsYzRjyGRYZPRlhGWMZZRlnGWkZaxltGW4ZcBl9GY4ZkBmSGZQZlhmYGZoZnBmeGa8ZsRmzGbUZtxm5GbsZvRm/GcEaABoCGgQaBhoIGgkaChoLGgwaDhoQGhEaEhoUGhUaVBpWGlgaWhpcGl0aXhpfGmAaYhpkGmUaZhpoGmkaqBqqGqwarhqwGrEashqzGrQathq4Grkauhq8Gr0ayhrLGswazhsNGw8bERsTGxUbFhsXGxgbGRsbGx0bHhsfGyEbIhthG2MbZRtnG2kbahtrG2wbbRtvG3EbchtzG3Ubdhu1G7cbuRu7G70bvhu/G8AbwRvDG8UbxhvHG8kbyhwJHAscDRwPHBEcEhwTHBQcFRwXHBkcGhwbHB0cHhxdHF8cYRxjHGUcZhxnHGgcaRxrHG0cbhxvHHEcchyXHLsc4h0GHQgdCh0MHQ4dEB0SHRMdFR0iHTEdMx01HTcdOR07HT0dPx1OHVAdUh1UHVYdWB1aHVwdXh2dHZ8doR2jHaUdph2nHagdqR2rHa0drh2vHbEdsh20HfMd9R33Hfkd+x38Hf0d/h3/HgEeAx4EHgUeBx4IHkceSR5LHk0eTx5QHlEeUh5THlUeVx5YHlkeWx5cHpsenR6fHqEeox6kHqUeph6nHqkeqx6sHq0erx6wHrIe8R7zHvUe9x75Hvoe+x78Hv0e/x8BHwIfAx8FHwYfRR9HH0kfSx9NH04fTx9QH1EfUx9VH1YfVx9ZH1ofmR+bH50fnx+hH6Ifox+kH6Ufpx+pH6ofqx+tH64fuR/CH8MfxR/OH9kf6B/zIAEgFiAqIEEgUyBgIGEgYiBkIHEgciBzIHUggiCDIIQghiCPIJ4gqyC6IMwg4CD3IQkhEiETIRUhIiEjISQhJiEnITAhOiFBAAAAAAAAAgIAAAAAAAAEMAAAAAAAAAAAAAAAAAAAIUk= + + + + \ No newline at end of file diff --git a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V1.swift b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V1.swift index 029c77e..a624104 100644 --- a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V1.swift +++ b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V1.swift @@ -18,7 +18,7 @@ extension Advanced.EvolutionDemo { // MARK: Internal - static let name: ModelVersion = "Advanced.Evolution.V1" + static let name: ModelVersion = "Advanced.EvolutionDemo.V1" typealias Creature = Advanced_EvolutionDemo_V1_Creature } diff --git a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V2.Creature.swift b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V2.Creature.swift index 1e39fd8..41e2d00 100644 --- a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V2.Creature.swift +++ b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V2.Creature.swift @@ -42,6 +42,31 @@ final class Advanced_EvolutionDemo_V2_Creature: NSManagedObject, Advanced.Evolut // MARK: Advanced.EvolutionDemo.CreatureType + + static func dataSource(in dataStack: DataStack) -> Advanced.EvolutionDemo.CreaturesDataSource { + + return .init( + listPublisher: dataStack.publishList( + From() + .orderBy(.descending(\.dnaCode)) + ), + dataStack: dataStack + ) + } + + static func count(in transaction: BaseDataTransaction) throws -> Int { + + return try transaction.fetchCount( + From() + ) + } + + static func create(in transaction: BaseDataTransaction) -> Advanced.EvolutionDemo.V2.Creature { + + return transaction.create( + Into() + ) + } func mutate(in transaction: BaseDataTransaction) { diff --git a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V2.FromV1.swift b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V2.FromV1.swift new file mode 100644 index 0000000..16eafd4 --- /dev/null +++ b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V2.FromV1.swift @@ -0,0 +1,27 @@ +// +// Demo +// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved. + +import CoreStore + + +// MARK: - Advanced.EvolutionDemo.V2 + +extension Advanced.EvolutionDemo.V2 { + + // MARK: - Advanced.EvolutionDemo.V2.FromV1 + + enum FromV1 { + + // MARK: Internal + + static var mapping: XcodeSchemaMappingProvider { + + return XcodeSchemaMappingProvider( + from: Advanced.EvolutionDemo.V1.name, + to: Advanced.EvolutionDemo.V2.name, + mappingModelBundle: Bundle(for: Advanced.EvolutionDemo.V1.Creature.self) + ) + } + } +} diff --git a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V2.FromV1.xcmappingmodel/xcmapping.xml b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V2.FromV1.xcmappingmodel/xcmapping.xml new file mode 100644 index 0000000..8cfe9c5 --- /dev/null +++ b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V2.FromV1.xcmappingmodel/xcmapping.xml @@ -0,0 +1,97 @@ + + + + + + 134481920 + 3F477D57-4044-4E9E-9845-6B9B63B11BB7 + 108 + + + + NSPersistenceFrameworkVersion + 977 + NSStoreModelVersionHashes + + XDDevAttributeMapping + + 0plcXXRN7XHKl5CcF+fwriFmUpON3ZtcI/AfK748aWc= + + XDDevEntityMapping + + qeN1Ym3TkWN1G6dU9RfX6Kd2ccEvcDVWHpd3LpLgboI= + + XDDevMappingModel + + EqtMzvRnVZWkXwBHu4VeVGy8UyoOe+bi67KC79kphlQ= + + XDDevPropertyMapping + + XN33V44TTGY4JETlMoOB5yyTKxB+u4slvDIinv0rtGA= + + XDDevRelationshipMapping + + akYY9LhehVA/mCb4ATLWuI9XGLcjpm14wWL1oEBtIcs= + + + NSStoreModelVersionHashesDigest + +Hmc2uYZK6og+Pvx5GUJ7oW75UG4V/ksQanTjfTKUnxyGWJRMtB5tIRgVwGsrd7lz/QR57++wbvWsr6nxwyS0A== + NSStoreModelVersionHashesVersion + 3 + NSStoreModelVersionIdentifiers + + + + + + + + + Advanced_EvolutionDemo_V2_FromV1MigrationPolicy + Creature + Undefined + 1 + Creature + 1 + + + + + + dnaCode + + + + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMSAAGGoF8Q +D05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGsCwwXGB0eJiswMTQ4VSRudWxs1Q0ODxAREhMUFRZZTlNPcGVyYW5kXk5TU2VsZWN0b3JOYW1lXxAQTlNFeHByZXNzaW9uVHlwZVtOU0FyZ3VtZW50c1YkY2xhc3OAA4ACEASABoALXxAQdmFsdWVGb3JLZXlQYXRoOtMZDxEaGxxaTlNWYXJpYWJsZYAEEAKABVZzb3VyY2XSHyAhIlokY2xhc3NuYW1lWCRjbGFzc2VzXxAUTlNWYXJpYWJsZUV4cHJlc3Npb26jIyQlXxAUTlNWYXJpYWJsZUV4cHJlc3Npb25cTlNFeHByZXNzaW9uWE5TT2JqZWN00icRKCpaTlMub2JqZWN0c6EpgAeACtMRDywtLi9ZTlNLZXlQYXRogAkQCoAIXxAQbnVtYmVyT2ZGbGFnZWxsYdIfIDIzXxAcTlNLZXlQYXRoU3BlY2lmaWVyRXhwcmVzc2lvbqMyJCXSHyA1Nl5OU011dGFibGVBcnJheaM1NyVXTlNBcnJhedIfIDk6XxATTlNLZXlQYXRoRXhwcmVzc2lvbqQ5OyQlXxAUTlNGdW5jdGlvbkV4cHJlc3Npb24ACAARABoAJAApADIANwBJAEwAUQBTAGAAZgBxAHsAigCdAKkAsACyALQAtgC4ALoAzQDUAN8A4QDjAOUA7ADxAPwBBQEcASABNwFEAU0BUgFdAV8BYQFjAWoBdAF2AXgBegGNAZIBsQG1AboByQHNAdUB2gHwAfUAAAAAAAACAQAAAAAAAAA8AAAAAAAAAAAAAAAAAAACDA== + + numberOfFlippers + + + + ⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V1.xcdatamodeld/Advanced.EvolutionDemo.V1.xcdatamodel + YnBsaXN0MDDUAAEAAgADAAQABQAGAAcAClgkdmVyc2lvblkkYXJjaGl2ZXJUJHRvcFgkb2JqZWN0 +cxIAAYagXxAPTlNLZXllZEFyY2hpdmVy0QAIAAlUcm9vdIABrxB/AAsADAAbADcAOAA5AEEAQgBdAF4AXwBlAGYAcgCIAIkAigCLAIwAjQCOAI8AkACRAKoArQC0ALoAyQDYANsA6gD5APwAXAEMARsBHwEjATIBOAE5AUEBUAFRAVoBYgFjAWQBeQF6AYIBgwGEAZABpAGlAaYBpwGoAakBqgGrAawBuwHKAdkB3QHsAfsCCgIZAigCNAJGAkcCSAJJAkoCSwJMAk0CXAJdAmwCewKKAosCmgKpArgCwALVAtYC3gLqAv4DDQMcAysDLwM+A00DXANrA3oDhgOYA6cDqAO3A8YD1QPWA+UD9AQDBAQEBwQQBBQEGAQcBCQEJwQrBCxVJG51bGzXAA0ADgAPABAAEQASABMAFAAVABYAFwAYABcAGl8QD194ZF9yb290UGFja2FnZVYkY2xhc3NcX3hkX2NvbW1lbnRzXxAQX3hkX21vZGVsTWFuYWdlcl8QFV9jb25maWd1cmF0aW9uc0J5TmFtZV1feGRfbW9kZWxOYW1lXxAXX21vZGVsVmVyc2lvbklkZW50aWZpZXKAAoB+gHuAAIB8gACAfd4AHAAdAB4AHwAgACEAIgAOACMAJAAlACYAJwAoACkAKgArAAkAKQAXAC8AMAAxADIAMwApACkAF18QHFhEQnVja2V0Rm9yQ2xhc3Nlc3dhc0VuY29kZWRfEBpYREJ1Y2tldEZvclBhY2thZ2Vzc3RvcmFnZV8QHFhEQnVja2V0Rm9ySW50ZXJmYWNlc3N0b3JhZ2VfEA9feGRfb3duaW5nTW9kZWxfEB1YREJ1Y2tldEZvclBhY2thZ2Vzd2FzRW5jb2RlZFZfb3duZXJfEBtYREJ1Y2tldEZvckRhdGFUeXBlc3N0b3JhZ2VbX3Zpc2liaWxpdHlfEBlYREJ1Y2tldEZvckNsYXNzZXNzdG9yYWdlVV9uYW1lXxAfWERCdWNrZXRGb3JJbnRlcmZhY2Vzd2FzRW5jb2RlZF8QHlhEQnVja2V0Rm9yRGF0YVR5cGVzd2FzRW5jb2RlZF8QEF91bmlxdWVFbGVtZW50SUSABIB5gHeAAYAEgACAeIB6EACABYADgASABIAAUFNZRVPTADoAOwAOADwAPgBAV05TLmtleXNaTlMub2JqZWN0c6EAPYAGoQA/gAeAJVhDcmVhdHVyZd8QEABDAEQARQBGACEARwBIACMASQBKAA4AJQBLAEwAKABNAE4ATwApACkAFABTAFQAMQApAE4AVwA9AE4AWgBbAFxfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2VfECBYREJ1Y2tldEZvclN0ZXJlb3R5cGVzd2FzRW5jb2RlZF8QJFhEQnVja2V0Rm9yT3duZWRBdHRyaWJ1dGVzd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNzdG9yYWdlXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNkdXBsaWNhdGVzXxAkWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnN3YXNFbmNvZGVkXxAdWERCdWNrZXRGb3JTdGVyZW90eXBlc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc29yZGVyZWRfECFYREJ1Y2tldEZvckdlbmVyYWxpemF0aW9uc3N0b3JhZ2VbX2lzQWJzdHJhY3SACYAtgASABIACgAqAdIAEgAmAdoAGgAmAdYAICBMAAAABAdFnUVdvcmRlcmVk0wA6ADsADgBgAGIAQKEAYYALoQBjgAyAJV5YRF9QU3RlcmVvdHlwZdkAIQAlAGcADgAoAGgAIwBNAGkAPwBhAE4AbQAXACkAMQBcAHFfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAB4ALgAmALIAAgAQIgA3TADoAOwAOAHMAfQBAqQB0AHUAdgB3AHgAeQB6AHsAfIAOgA+AEIARgBKAE4AUgBWAFqkAfgB/AIAAgQCCAIMAhACFAIaAF4AbgByAHoAfgCGAI4AmgCqAJV8QE1hEUE1Db21wb3VuZEluZGV4ZXNfEBBYRF9QU0tfZWxlbWVudElEXxAZWERQTVVuaXF1ZW5lc3NDb25zdHJhaW50c18QGlhEX1BTS192ZXJzaW9uSGFzaE1vZGlmaWVyXxAZWERfUFN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cGJ4YnxihGKIYpBimGKcYqBiqGKsYsBi9GMIYxBjGGMsYzRjPGNEY9hkaGUEZZRlnGWkZaxltGW8ZcRlyGXQZgRmSGZQZlhmYGZoZnBmeGaAZohmzGbUZtxm5GbsZvRm/GcEZwxnFGgQaBhoIGgoaDBoNGg4aDxoQGhIaFBoVGhYaGBoZGlgaWhpcGl4aYBphGmIaYxpkGmYaaBppGmoabBptGqwarhqwGrIatBq1GrYatxq4GroavBq9Gr4awBrBGs4azxrQGtIbERsTGxUbFxsZGxobGxscGx0bHxshGyIbIxslGyYbZRtnG2kbaxttG24bbxtwG3Ebcxt1G3Ybdxt5G3obuRu7G70bvxvBG8IbwxvEG8UbxxvJG8obyxvNG84cDRwPHBEcExwVHBYcFxwYHBkcGxwdHB4cHxwhHCIcYRxjHGUcZxxpHGocaxxsHG0cbxxxHHIccxx1HHYcmxy/HOYdCh0MHQ4dEB0SHRQdFh0XHRkdJh01HTcdOR07HT0dPx1BHUMdUh1UHVYdWB1aHVwdXh1gHWIdoR2jHaUdpx2pHaodqx2sHa0drx2xHbIdsx21HbYduB33Hfkd+x39Hf8eAB4BHgIeAx4FHgceCB4JHgseDB5LHk0eTx5RHlMeVB5VHlYeVx5ZHlseXB5dHl8eYB6fHqEeox6lHqceqB6pHqoeqx6tHq8esB6xHrMetB62HvUe9x75Hvse/R7+Hv8fAB8BHwMfBR8GHwcfCR8KH0kfSx9NH08fUR9SH1MfVB9VH1cfWR9aH1sfXR9eH50fnx+hH6MfpR+mH6cfqB+pH6sfrR+uH68fsR+yH70fxh/HH8kf0h/dH+wf9yAFIBogLiBFIFcgZCBlIGYgaCB1IHYgdyB5IIYghyCIIIogkyCiIK8gviDQIOQg+yENIRYhFyEZISYhJyEoISohKyE0IT4hRQAAAAAAAAICAAAAAAAABDAAAAAAAAAAAAAAAAAAACFN + + ⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V1.xcdatamodeld/Advanced.EvolutionDemo.V2.xcdatamodel + YnBsaXN0MDDUAAEAAgADAAQABQAGAAcAClgkdmVyc2lvblkkYXJjaGl2ZXJUJHRvcFgkb2JqZWN0 +cxIAAYagXxAPTlNLZXllZEFyY2hpdmVy0QAIAAlUcm9vdIABrxDJAAsADAAbADcAOAA5AEEAQgBdAF4AXwBlAGYAcgCIAIkAigCLAIwAjQCOAI8AkACRAKoArQC0ALoAyQDYANsA6gD5APwAXAEMARsBHwEjATIBOAE5AUEBUAFRAVoBaAFpAWoBawFsAW0BggGDAYsBjAGNAZkBrQGuAa8BsAGxAbIBswG0AbUBxAHTAeIB5gH1AgQCEwIiAjECPQJPAlACUQJSAlMCVAJVAlYCZQJmAnUChAKTApQCowKyAsECyQLeAt8C5wLzAwcDFgMlAzQDOANHA1YDZQN0A4MDjwOhA7ADvwPOA90D7AP7BAoEHwQgBCgENARIBFcEZgR1BHkEiASXBKYEtQTEBNAE4gTxBPIFAQUQBR8FIAUvBT4FTQViBWMFawV3BYsFmgWpBbgFvAXLBdoF6QX4BgcGEwYlBjQGNQZEBlMGYgZjBnIGgQaQBqUGpgauBroGzgbdBuwG+wb/Bw4HHQcsBzsHSgdWB2gHdweGB5UHpAezB8IH0QfSB9UH3gfiB+YH6gfyB/UH+Qf6VSRudWxs1wANAA4ADwAQABEAEgATABQAFQAWABcAGAAXABpfEA9feGRfcm9vdFBhY2thZ2VWJGNsYXNzXF94ZF9jb21tZW50c18QEF94ZF9tb2RlbE1hbmFnZXJfEBVfY29uZmlndXJhdGlvbnNCeU5hbWVdX3hkX21vZGVsTmFtZV8QF19tb2RlbFZlcnNpb25JZGVudGlmaWVygAKAyIDFgACAxoAAgMfeABwAHQAeAB8AIAAhACIADgAjACQAJQAmACcAKAApACoAKwAJACkAFwAvADAAMQAyADMAKQApABdfEBxYREJ1Y2tldEZvckNsYXNzZXN3YXNFbmNvZGVkXxAaWERCdWNrZXRGb3JQYWNrYWdlc3N0b3JhZ2VfEBxYREJ1Y2tldEZvckludGVyZmFjZXNzdG9yYWdlXxAPX3hkX293bmluZ01vZGVsXxAdWERCdWNrZXRGb3JQYWNrYWdlc3dhc0VuY29kZWRWX293bmVyXxAbWERCdWNrZXRGb3JEYXRhVHlwZXNzdG9yYWdlW192aXNpYmlsaXR5XxAZWERCdWNrZXRGb3JDbGFzc2Vzc3RvcmFnZVVfbmFtZV8QH1hEQnVja2V0Rm9ySW50ZXJmYWNlc3dhc0VuY29kZWRfEB5YREJ1Y2tldEZvckRhdGFUeXBlc3dhc0VuY29kZWRfEBBfdW5pcXVlRWxlbWVudElEgASAw4DBgAGABIAAgMKAxBAAgAWAA4AEgASAAFBTWUVT0wA6ADsADgA8AD4AQFdOUy5rZXlzWk5TLm9iamVjdHOhAD2ABqEAP4AHgCVYQ3JlYXR1cmXfEBAAQwBEAEUARgAhAEcASAAjAEkASgAOACUASwBMACgATQBOAE8AKQApABQAUwBUADEAKQBOAFcAPQBOAFoAWwBcXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zZHVwbGljYXRlc18QJFhEQnVja2V0Rm9yR2VuZXJhbGl6YXRpb25zd2FzRW5jb2RlZF8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNvcmRlcmVkXxAhWERCdWNrZXRGb3JHZW5lcmFsaXphdGlvbnNzdG9yYWdlW19pc0Fic3RyYWN0gAmALYAEgASAAoAKgL6ABIAJgMCABoAJgL+ACAgScIBBUFdvcmRlcmVk0wA6ADsADgBgAGIAQKEAYYALoQBjgAyAJV5YRF9QU3RlcmVvdHlwZdkAIQAlAGcADgAoAGgAIwBNAGkAPwBhAE4AbQAXACkAMQBcAHFfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc29yZGVyZWRfECRYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3dhc0VuY29kZWRfECFYREJ1Y2tldEZvck93bmVkQXR0cmlidXRlc3N0b3JhZ2WAB4ALgAmALIAAgAQIgA3TADoAOwAOAHMAfQBAqQB0AHUAdgB3AHgAeQB6AHsAfIAOgA+AEIARgBKAE4AUgBWAFqk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lAWIBYwFkAWUBZoAzgF6AdYCOgKeAJVxoYXNWZXJ0ZWJyYWVXaGFzVGFpbFdkbmFDb2RlXxAQbnVtYmVyT2ZGbGlwcGVyc1doYXNIZWFk3xASAJIAkwCUAW4AIQCWAJcBbwAjAJUBcACYAA4AJQCZAJoAKACbABcAFwAXACkAPwBcAFwBeAAxAFwATgBcAXwBXABcAFwBgABcXxAgWERCdWNrZXRGb3JTdGVyZW90eXBlc3dhc0VuY29kZWRfEB1YREJ1Y2tldEZvclN0ZXJlb3R5cGVzc3RvcmFnZV8QHVhEQnVja2V0Rm9yU3RlcmVvdHlwZXNvcmRlcmVkgACAAIAAgASABwgIgDUIgAkIgF2ALggIgDQIEq4v1IjTADoAOwAOAYQBhwBAogGFAYaANoA3ogGIAYmAOIBLgCVfEBJYRF9QUHJvcFN0ZXJlb3R5cGVfEBJYRF9QQXR0X1N0ZXJlb3R5cGXZACEAJQGOAA4AKAGPACMATQGQAWIBhQBOAG0AFwApADEAXAGYXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNvcmRlcmVkXxAkWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXN3YXNFbmNvZGVkXxAhWERCdWNrZXRGb3JPd25lZEF0dHJpYnV0ZXNzdG9yYWdlgDOANoAJgCyAAIAECIA50wA6ADsADgGaAaMAQKgBmwGcAZ0BngGfAaABoQGigDqAO4A8gD2APoA/gECAQagBpAGlAaYBpwGoAakBqgGrgEKAQ4BEgEaAR4BIgEmASoAlXxAbWERfUFBTS19pc1N0b3JlZEluVHJ1dGhGaWxlXxAbWERfUFBTS192ZXJzaW9uSGFzaE1vZGlmaWVyXxAQWERfUFBTS191c2VySW5mb18QEVhEX1BQU0tfaXNJbmRleGVkXxASWERfUFBTS19pc09wdGlvbmFsXxAaWERfUFBTS19pc1Nwb3RsaWdodEluZGV4ZWRfEBFYRF9QUFNLX2VsZW1lbnRJRF8QE1hEX1BQU0tfaXNUcmFuc2llbnTfEA8AkgCTAJQAIQCVAJYAlwAjAJgADgAlAJkAmgAoAJsAFwD+ABcBiABcAFwAXAAxAFwApAGbAFwAXAAXAFyAAIAigACAOAgICAiAGoA6CAiAAAjfEA8AkgCTAJQAIQCVAJYAlwAjAJg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AGoIahBqGGogaihqMGo4akBrPGtEa0xrVGtca2BrZGtoa2xrdGt8a4BrhGuMa5BsjGyUbJxspGysbLBstGy4bLxsxGzMbNBs1GzcbOBt3G3kbext9G38bgBuBG4IbgxuFG4cbiBuJG4sbjBuZG5obmxudG9wb3hvgG+Ib5BvlG+Yb5xvoG+ob7BvtG+4b8BvxHDAcMhw0HDYcOBw5HDocOxw8HD4cQBxBHEIcRBxFHIQchhyIHIocjByNHI4cjxyQHJIclByVHJYcmByZHNgc2hzcHN4c4BzhHOIc4xzkHOYc6BzpHOoc7BztHSwdLh0wHTIdNB01HTYdNx04HTodPB09HT4dQB1BHWYdih2xHdUd1x3ZHdsd3R3fHeEd4h3kHfEeAB4CHgQeBh4IHgoeDB4OHh0eHx4hHiMeJR4nHikeKx4tHmwebh5wHnIedB51HnYedx54HnoefB59Hn4egB6BHsAewh7EHsYeyB7JHsoeyx7MHs4e0B7RHtIe1B7VHxQfFh8YHxofHB8dHx4fHx8gHyIfJB8lHyYfKB8pH2gfah9sH24fcB9xH3Ifcx90H3YfeB95H3offB99H7wfvh/AH8IfxB/FH8Yfxx/IH8ofzB/NH84f0B/RIBAgEiAUIBYgGCAZIBogGyAcIB4gICAhICIgJCAlIGQgZiBoIGogbCBtIG4gbyBwIHIgdCB1IHYgeCB5IMQg5yEHISchKSErIS0hLyExITIhMyE1ITYhOCE5ITshPSE+IT8hQSFCIUchVCFZIVshXSFiIWQhZiFoIY0hsSHYIfwh/iIAIgIiBCIGIggiCSILIhgiKSIrIi0iLyIxIjMiNSI3IjkiSiJMIk4iUCJSIlQiViJYIloiXCKbIp0inyKhIqMipCKlIqYipyKpIqsirCKtIq8isCLvIvEi8yL1Ivci+CL5Ivoi+yL9Iv8jACMBIwMjBCNDI0UjRyNJI0sjTCNNI04jTyNRI1MjVCNVI1cjWCNlI2YjZyNpI6gjqiOsI64jsCOxI7IjsyO0I7YjuCO5I7ojvCO9I/wj/iQAJAIkBCQFJAYkByQIJAokDCQNJA4kECQRJFAkUiRUJFYkWCRZJFokWyRcJF4kYCRhJGIkZCRlJKQkpiSoJKokrCStJK4krySwJLIktCS1JLYkuCS5JPgk+iT8JP4lACUBJQIlAyUEJQYlCCU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 + + + + + hasVertebrae + + + + YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMSAAGGoF8Q +D05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGkCwwTFFUkbnVsbNMNDg8QERJfEA9OU0NvbnN0YW50VmFsdWVfEBBOU0V4cHJlc3Npb25UeXBlViRjbGFzc4ACEACAAwnSFRYXGFokY2xhc3NuYW1lWCRjbGFzc2VzXxAZTlNDb25zdGFudFZhbHVlRXhwcmVzc2lvbqMXGRpcTlNFeHByZXNzaW9uWE5TT2JqZWN0CBEaJCkyN0lMUVNYXmV3ipGTlZeYnaixzdHeAAAAAAAAAQEAAAAAAAAAGwAAAAAAAAAAAAAAAAAAAOc= + + hasHead + + + + hasTail + + + \ No newline at end of file diff --git a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V2.FromV1MigrationPolicy.swift b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V2.FromV1MigrationPolicy.swift new file mode 100644 index 0000000..438ad04 --- /dev/null +++ b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V2.FromV1MigrationPolicy.swift @@ -0,0 +1,40 @@ +// +// Demo +// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved. + +import CoreData +import CoreStore + + +// MARK: - Advanced.EvolutionDemo.V2.FromV1MigrationPolicy + +@objc(Advanced_EvolutionDemo_V2_FromV1MigrationPolicy) +final class Advanced_EvolutionDemo_V2_FromV1MigrationPolicy: NSEntityMigrationPolicy { + + // MARK: NSEntityMigrationPolicy + + override func createDestinationInstances( + forSource sInstance: NSManagedObject, + in mapping: NSEntityMapping, + manager: NSMigrationManager + ) throws { + + try super.createDestinationInstances( + forSource: sInstance, + in: mapping, + manager: manager + ) + + for dInstance in manager.destinationInstances(forEntityMappingName: mapping.name, sourceInstances: [sInstance]) { + + dInstance.setValue( + Bool.random(), + forKey: #keyPath(Advanced.EvolutionDemo.V2.Creature.hasVertebrae) + ) + dInstance.setValue( + Bool.random(), + forKey: #keyPath(Advanced.EvolutionDemo.V2.Creature.hasTail) + ) + } + } +} diff --git a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V2.FromV3.swift b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V2.FromV3.swift new file mode 100644 index 0000000..cff040c --- /dev/null +++ b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V2.FromV3.swift @@ -0,0 +1,41 @@ +// +// Demo +// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved. + +import CoreStore + + +// MARK: - Advanced.EvolutionDemo.V2 + +extension Advanced.EvolutionDemo.V2 { + + // MARK: - Advanced.EvolutionDemo.V2.FromV3 + + enum FromV3 { + + // MARK: Internal + + static var mapping: CustomSchemaMappingProvider { + + return CustomSchemaMappingProvider( + from: Advanced.EvolutionDemo.V3.name, + to: Advanced.EvolutionDemo.V2.name, + entityMappings: [ + .transformEntity( + sourceEntity: "Creature", + destinationEntity: "Creature", + transformer: { (source, createDestination) in + + let destination = createDestination() + destination["dnaCode"] = source["dnaCode"] + destination["numberOfFlippers"] = source["numberOfLimbs"] + destination["hasVertebrae"] = source["hasVertebrae"] + destination["hasHead"] = source["hasHead"] + destination["hasTail"] = source["hasTail"] + } + ) + ] + ) + } + } +} diff --git a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V2.swift b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V2.swift index abd5fae..996c1d5 100644 --- a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V2.swift +++ b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V2.swift @@ -18,8 +18,10 @@ extension Advanced.EvolutionDemo { // MARK: Internal - static let name: ModelVersion = "Advanced.Evolution.V2" + static let name: ModelVersion = "Advanced.EvolutionDemo.V2" typealias Creature = Advanced_EvolutionDemo_V2_Creature + + typealias FromV1MigrationPolicy = Advanced_EvolutionDemo_V2_FromV1MigrationPolicy } } diff --git a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V3.Creature.swift b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V3.Creature.swift index 9446450..aab4fa4 100644 --- a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V3.Creature.swift +++ b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V3.Creature.swift @@ -64,6 +64,31 @@ extension Advanced.EvolutionDemo.V3 { // MARK: Advanced.EvolutionDemo.CreatureType + + static func dataSource(in dataStack: DataStack) -> Advanced.EvolutionDemo.CreaturesDataSource { + + return .init( + listPublisher: dataStack.publishList( + From() + .orderBy(.descending(\.$dnaCode)) + ), + dataStack: dataStack + ) + } + + static func count(in transaction: BaseDataTransaction) throws -> Int { + + return try transaction.fetchCount( + From() + ) + } + + static func create(in transaction: BaseDataTransaction) -> Advanced.EvolutionDemo.V3.Creature { + + return transaction.create( + Into() + ) + } func mutate(in transaction: BaseDataTransaction) { diff --git a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V3.FromV2.swift b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V3.FromV2.swift new file mode 100644 index 0000000..5364c72 --- /dev/null +++ b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V3.FromV2.swift @@ -0,0 +1,43 @@ +// +// Demo +// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved. + +import CoreStore + + +// MARK: - Advanced.EvolutionDemo.V3 + +extension Advanced.EvolutionDemo.V3 { + + // MARK: - Advanced.EvolutionDemo.V3.FromV2 + + enum FromV2 { + + // MARK: Internal + + static var mapping: CustomSchemaMappingProvider { + + return CustomSchemaMappingProvider( + from: Advanced.EvolutionDemo.V2.name, + to: Advanced.EvolutionDemo.V3.name, + entityMappings: [ + .transformEntity( + sourceEntity: "Creature", + destinationEntity: "Creature", + transformer: { (source, createDestination) in + + let destination = createDestination() + destination["dnaCode"] = source["dnaCode"] + destination["numberOfLimbs"] = source["numberOfFlippers"] + destination["hasVertebrae"] = source["hasVertebrae"] + destination["hasHead"] = source["hasHead"] + destination["hasTail"] = source["hasTail"] + destination["hasWings"] = Bool.random() + destination["habitat"] = Advanced.EvolutionDemo.V3.Creature.Habitat.allCases.randomElement()!.rawValue + } + ) + ] + ) + } + } +} diff --git a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V3.FromV4.swift b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V3.FromV4.swift new file mode 100644 index 0000000..6fc30db --- /dev/null +++ b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V3.FromV4.swift @@ -0,0 +1,33 @@ +// +// Demo +// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved. + +import CoreStore + + +// MARK: - Advanced.EvolutionDemo.V3 + +extension Advanced.EvolutionDemo.V3 { + + // MARK: - Advanced.EvolutionDemo.V3.FromV4 + + enum FromV4 { + + // MARK: Internal + + static var mapping: CustomSchemaMappingProvider { + + return CustomSchemaMappingProvider( + from: Advanced.EvolutionDemo.V4.name, + to: Advanced.EvolutionDemo.V3.name, + entityMappings: [ + .transformEntity( + sourceEntity: "Creature", + destinationEntity: "Creature", + transformer: CustomSchemaMappingProvider.CustomMapping.inferredTransformation(_:_:) + ) + ] + ) + } + } +} diff --git a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V3.swift b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V3.swift index 7437d39..28ba426 100644 --- a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V3.swift +++ b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V3.swift @@ -18,6 +18,6 @@ extension Advanced.EvolutionDemo { // MARK: Internal - static let name: ModelVersion = "Advanced.Evolution.V3" + static let name: ModelVersion = "Advanced.EvolutionDemo.V3" } } diff --git a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V4.Creature.swift b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V4.Creature.swift index 99bc5ae..da7989d 100644 --- a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V4.Creature.swift +++ b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V4.Creature.swift @@ -60,6 +60,31 @@ extension Advanced.EvolutionDemo.V4 { // MARK: Advanced.EvolutionDemo.CreatureType + + static func dataSource(in dataStack: DataStack) -> Advanced.EvolutionDemo.CreaturesDataSource { + + return .init( + listPublisher: dataStack.publishList( + From() + .orderBy(.descending(\.$dnaCode)) + ), + dataStack: dataStack + ) + } + + static func count(in transaction: BaseDataTransaction) throws -> Int { + + return try transaction.fetchCount( + From() + ) + } + + static func create(in transaction: BaseDataTransaction) -> Advanced.EvolutionDemo.V4.Creature { + + return transaction.create( + Into() + ) + } func mutate(in transaction: BaseDataTransaction) { diff --git a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V4.FromV3.swift b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V4.FromV3.swift new file mode 100644 index 0000000..a54be1c --- /dev/null +++ b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V4.FromV3.swift @@ -0,0 +1,44 @@ +// +// Demo +// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved. + +import CoreStore + + +// MARK: - Advanced.EvolutionDemo.V4 + +extension Advanced.EvolutionDemo.V4 { + + // MARK: - Advanced.EvolutionDemo.V4.FromV3 + + enum FromV3 { + + // MARK: Internal + + static var mapping: CustomSchemaMappingProvider { + + return CustomSchemaMappingProvider( + from: Advanced.EvolutionDemo.V3.name, + to: Advanced.EvolutionDemo.V4.name, + entityMappings: [ + .transformEntity( + sourceEntity: "Creature", + destinationEntity: "Creature", + transformer: { (source, createDestination) in + + let destination = createDestination() + destination.enumerateAttributes { (destinationAttribute, sourceAttribute) in + + if let sourceAttribute = sourceAttribute { + + destination[destinationAttribute] = source[sourceAttribute] + } + } + destination["isWarmBlooded"] = Bool.random() + } + ) + ] + ) + } + } +} diff --git a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V4.swift b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V4.swift index 6b2738d..0f40bb7 100644 --- a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V4.swift +++ b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.V4.swift @@ -18,6 +18,6 @@ extension Advanced.EvolutionDemo { // MARK: Internal - static let name: ModelVersion = "Advanced.Evolution.V4" + static let name: ModelVersion = "Advanced.EvolutionDemo.V4" } } diff --git a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.swift b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.swift index 96315f9..5ffe60b 100644 --- a/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.swift +++ b/Demo/⭐️Sources/⭐️Demos/⭐️Advanced/EvolutionDemo/Advanced.EvolutionDemo.swift @@ -9,7 +9,7 @@ extension Advanced { // MARK: - Advanced.EvolutionDemo /** - Sample execution of progressive migrations. This demo also supports backwards migration. + Sample execution of progressive migrations. This demo also shows how to do two-way migration chains (upgrades+downgrades), while allowing the app to use any version of the model. */ enum EvolutionDemo {} } diff --git a/Sources/DynamicObject.swift b/Sources/DynamicObject.swift index 21060df..48dd3e7 100644 --- a/Sources/DynamicObject.swift +++ b/Sources/DynamicObject.swift @@ -33,10 +33,6 @@ import CoreData All CoreStore's utilities are designed around `DynamicObject` instances. `NSManagedObject` and `CoreStoreObject` instances all conform to `DynamicObject`. */ public protocol DynamicObject: AnyObject { - /** - The object ID for this instance - */ - typealias ObjectID = NSManagedObjectID /** Used internally by CoreStore. Do not call directly. @@ -72,6 +68,11 @@ public protocol DynamicObject: AnyObject { extension DynamicObject { // MARK: Internal + + /** + The object ID for this instance + */ + public typealias ObjectID = NSManagedObjectID internal func runtimeType() -> Self.Type {