From bea067cd1de36ef517775e16819f5814f1e520f1 Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Sun, 19 Jul 2020 00:13:35 -0400 Subject: [PATCH 01/30] move stuff around --- ParseSwift.xcodeproj/project.pbxproj | 88 +++++++------- .../{AnyCodable => Coding}/AnyCodable.swift | 0 .../{AnyCodable => Coding}/AnyDecodable.swift | 0 .../{AnyCodable => Coding}/AnyEncodable.swift | 0 .../ObjectType.swift | 103 ----------------- .../{Encoder => Coding}/ParseEncoder.swift | 0 .../ObjectType+Equatable.swift | 18 --- .../Objects Protocols/ObjectType+Query.swift | 23 ---- Sources/ParseSwift/Objects/Fetchable.swift | 20 ++++ .../ParseObject+Batch.swift} | 0 Sources/ParseSwift/Objects/ParseObject.swift | 107 ++++++++++++++++++ Sources/ParseSwift/Objects/Queryable.swift | 29 +++++ Sources/ParseSwift/Objects/Saveable.swift | 20 ++++ .../UserType.swift | 3 + .../{Types => Parse Types}/ACL.swift | 0 .../{Types => Parse Types}/File.swift | 0 .../{Types => Parse Types}/GeoPoint.swift | 0 Sources/ParseSwift/Parse Types/NoBody.swift | 9 ++ .../{Types => Parse Types}/ParseError.swift | 0 .../{Types => Parse Types}/Pointer.swift | 0 .../{Types => Parse Types}/Query.swift | 19 +--- 21 files changed, 240 insertions(+), 199 deletions(-) rename Sources/ParseSwift/{AnyCodable => Coding}/AnyCodable.swift (100%) rename Sources/ParseSwift/{AnyCodable => Coding}/AnyDecodable.swift (100%) rename Sources/ParseSwift/{AnyCodable => Coding}/AnyEncodable.swift (100%) rename Sources/ParseSwift/{Objects Protocols => Coding}/ObjectType.swift (53%) rename Sources/ParseSwift/{Encoder => Coding}/ParseEncoder.swift (100%) delete mode 100644 Sources/ParseSwift/Objects Protocols/ObjectType+Equatable.swift delete mode 100644 Sources/ParseSwift/Objects Protocols/ObjectType+Query.swift create mode 100644 Sources/ParseSwift/Objects/Fetchable.swift rename Sources/ParseSwift/{Objects Protocols/ObjectType+Batch.swift => Objects/ParseObject+Batch.swift} (100%) create mode 100644 Sources/ParseSwift/Objects/ParseObject.swift create mode 100644 Sources/ParseSwift/Objects/Queryable.swift create mode 100644 Sources/ParseSwift/Objects/Saveable.swift rename Sources/ParseSwift/{Objects Protocols => Objects}/UserType.swift (99%) rename Sources/ParseSwift/{Types => Parse Types}/ACL.swift (100%) rename Sources/ParseSwift/{Types => Parse Types}/File.swift (100%) rename Sources/ParseSwift/{Types => Parse Types}/GeoPoint.swift (100%) create mode 100644 Sources/ParseSwift/Parse Types/NoBody.swift rename Sources/ParseSwift/{Types => Parse Types}/ParseError.swift (100%) rename Sources/ParseSwift/{Types => Parse Types}/Pointer.swift (100%) rename Sources/ParseSwift/{Types => Parse Types}/Query.swift (93%) diff --git a/ParseSwift.xcodeproj/project.pbxproj b/ParseSwift.xcodeproj/project.pbxproj index cbe504ea8..4506cc744 100644 --- a/ParseSwift.xcodeproj/project.pbxproj +++ b/ParseSwift.xcodeproj/project.pbxproj @@ -8,12 +8,10 @@ /* Begin PBXBuildFile section */ 4A2D8C811F48B3A900EE1FCC /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2D8C801F48B3A900EE1FCC /* ParseEncoder.swift */; }; - 4A2F14941F4A5E1E00A7A7EF /* ObjectType+Equatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14931F4A5E1E00A7A7EF /* ObjectType+Equatable.swift */; }; 4A2F14961F4A5F2900A7A7EF /* Responses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14951F4A5F2900A7A7EF /* Responses.swift */; }; - 4A2F14981F4A5F6900A7A7EF /* ObjectType+Batch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14971F4A5F6900A7A7EF /* ObjectType+Batch.swift */; }; + 4A2F14981F4A5F6900A7A7EF /* ParseObject+Batch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14971F4A5F6900A7A7EF /* ParseObject+Batch.swift */; }; 4A2F14991F4A5FB500A7A7EF /* Responses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14951F4A5F2900A7A7EF /* Responses.swift */; }; - 4A2F149A1F4A5FBA00A7A7EF /* ObjectType+Equatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14931F4A5E1E00A7A7EF /* ObjectType+Equatable.swift */; }; - 4A2F149B1F4A5FBA00A7A7EF /* ObjectType+Batch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14971F4A5F6900A7A7EF /* ObjectType+Batch.swift */; }; + 4A2F149B1F4A5FBA00A7A7EF /* ParseObject+Batch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14971F4A5F6900A7A7EF /* ParseObject+Batch.swift */; }; 4A65114F1F48E3F3005237DF /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2D8C801F48B3A900EE1FCC /* ParseEncoder.swift */; }; 4A6511501F48E400005237DF /* BatchUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC397711F488F9E00DEA9D3 /* BatchUtils.swift */; }; 4A6511511F48E406005237DF /* ACL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC3976F1F48778900DEA9D3 /* ACL.swift */; }; @@ -25,7 +23,6 @@ 4A82B7F71F254CCE0063D731 /* ObjectType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EC1F254B820063D731 /* ObjectType.swift */; }; 4A82B7F81F254CCE0063D731 /* Pointer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7F11F254B820063D731 /* Pointer.swift */; }; 4A82B7FF1F256A8F0063D731 /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7FE1F256A8F0063D731 /* Query.swift */; }; - 4A82B8011F256B330063D731 /* ObjectType+Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B8001F256B330063D731 /* ObjectType+Query.swift */; }; 4A99A4691F2650CA00D72A59 /* ParseMutationContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A99A4681F2650CA00D72A59 /* ParseMutationContainer.swift */; }; 4A99A46C1F2650FF00D72A59 /* AddUniqueOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A99A46B1F2650FF00D72A59 /* AddUniqueOperation.swift */; }; 4A99A46E1F26512100D72A59 /* IncrementOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A99A46D1F26512100D72A59 /* IncrementOperation.swift */; }; @@ -68,7 +65,6 @@ 4AFDA7331F26DAE1002AE4FC /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7F01F254B820063D731 /* File.swift */; }; 4AFDA7341F26DAE1002AE4FC /* Pointer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7F11F254B820063D731 /* Pointer.swift */; }; 4AFDA7351F26DAE1002AE4FC /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7FE1F256A8F0063D731 /* Query.swift */; }; - 4AFDA7361F26DAE1002AE4FC /* ObjectType+Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B8001F256B330063D731 /* ObjectType+Query.swift */; }; 4AFDA7391F26DAF8002AE4FC /* Parse.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AB8B4F71F254AE10070F682 /* Parse.h */; settings = {ATTRIBUTES = (Public, ); }; }; 709075C724B9117500B95310 /* AnyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709075C424B9117400B95310 /* AnyCodable.swift */; }; 709075C824B9117500B95310 /* AnyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709075C424B9117400B95310 /* AnyCodable.swift */; }; @@ -79,6 +75,16 @@ 7FFF552E2217E72A007C3B4E /* AnyEncodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FFF552B2217E729007C3B4E /* AnyEncodableTests.swift */; }; 7FFF552F2217E72A007C3B4E /* AnyCodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FFF552C2217E729007C3B4E /* AnyCodableTests.swift */; }; 7FFF55302217E72A007C3B4E /* AnyDecodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FFF552D2217E729007C3B4E /* AnyDecodableTests.swift */; }; + F927E37924C3D19900F8A143 /* ParseObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = F927E37824C3D19900F8A143 /* ParseObject.swift */; }; + F927E37A24C3D19900F8A143 /* ParseObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = F927E37824C3D19900F8A143 /* ParseObject.swift */; }; + F927E37C24C3D1FD00F8A143 /* Fetchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F927E37B24C3D1FD00F8A143 /* Fetchable.swift */; }; + F927E37D24C3D1FD00F8A143 /* Fetchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F927E37B24C3D1FD00F8A143 /* Fetchable.swift */; }; + F92B578724C3F02D00A43E8D /* Saveable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F92B578624C3F02D00A43E8D /* Saveable.swift */; }; + F92B578824C3F02D00A43E8D /* Saveable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F92B578624C3F02D00A43E8D /* Saveable.swift */; }; + F92B578A24C3F09600A43E8D /* Queryable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F92B578924C3F09600A43E8D /* Queryable.swift */; }; + F92B578B24C3F09600A43E8D /* Queryable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F92B578924C3F09600A43E8D /* Queryable.swift */; }; + F92B578D24C3F0F300A43E8D /* NoBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = F92B578C24C3F0F300A43E8D /* NoBody.swift */; }; + F92B578E24C3F0F300A43E8D /* NoBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = F92B578C24C3F0F300A43E8D /* NoBody.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -102,16 +108,14 @@ 4A1120BF1F49FC3300E32D94 /* LinuxMain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinuxMain.swift; sourceTree = ""; }; 4A2D8C801F48B3A900EE1FCC /* ParseEncoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseEncoder.swift; sourceTree = ""; }; 4A2F14901F4A41B900A7A7EF /* Asynchronous.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Asynchronous.swift; sourceTree = ""; }; - 4A2F14931F4A5E1E00A7A7EF /* ObjectType+Equatable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ObjectType+Equatable.swift"; sourceTree = ""; }; 4A2F14951F4A5F2900A7A7EF /* Responses.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Responses.swift; sourceTree = ""; }; - 4A2F14971F4A5F6900A7A7EF /* ObjectType+Batch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ObjectType+Batch.swift"; sourceTree = ""; }; + 4A2F14971F4A5F6900A7A7EF /* ParseObject+Batch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParseObject+Batch.swift"; sourceTree = ""; }; 4A82B7EC1F254B820063D731 /* ObjectType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObjectType.swift; sourceTree = ""; }; 4A82B7ED1F254B820063D731 /* GeoPoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoPoint.swift; sourceTree = ""; }; 4A82B7EE1F254B820063D731 /* Parse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Parse.swift; sourceTree = ""; }; 4A82B7F01F254B820063D731 /* File.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = File.swift; sourceTree = ""; }; 4A82B7F11F254B820063D731 /* Pointer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pointer.swift; sourceTree = ""; }; 4A82B7FE1F256A8F0063D731 /* Query.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Query.swift; sourceTree = ""; }; - 4A82B8001F256B330063D731 /* ObjectType+Query.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ObjectType+Query.swift"; sourceTree = ""; }; 4A99A4681F2650CA00D72A59 /* ParseMutationContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseMutationContainer.swift; sourceTree = ""; }; 4A99A46B1F2650FF00D72A59 /* AddUniqueOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddUniqueOperation.swift; sourceTree = ""; }; 4A99A46D1F26512100D72A59 /* IncrementOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncrementOperation.swift; sourceTree = ""; }; @@ -149,6 +153,11 @@ 7FFF552B2217E729007C3B4E /* AnyEncodableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyEncodableTests.swift; sourceTree = ""; }; 7FFF552C2217E729007C3B4E /* AnyCodableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyCodableTests.swift; sourceTree = ""; }; 7FFF552D2217E729007C3B4E /* AnyDecodableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyDecodableTests.swift; sourceTree = ""; }; + F927E37824C3D19900F8A143 /* ParseObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseObject.swift; sourceTree = ""; }; + F927E37B24C3D1FD00F8A143 /* Fetchable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Fetchable.swift; sourceTree = ""; }; + F92B578624C3F02D00A43E8D /* Saveable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Saveable.swift; sourceTree = ""; }; + F92B578924C3F09600A43E8D /* Queryable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Queryable.swift; sourceTree = ""; }; + F92B578C24C3F0F300A43E8D /* NoBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoBody.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -184,14 +193,6 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 4A2F149C1F4A604900A7A7EF /* Encoder */ = { - isa = PBXGroup; - children = ( - 4A2D8C801F48B3A900EE1FCC /* ParseEncoder.swift */, - ); - path = Encoder; - sourceTree = ""; - }; 4A5EE45F1F49E9E000D3CAE3 /* Sources */ = { isa = PBXGroup; children = ( @@ -217,17 +218,18 @@ path = "ParseSwift-iOS"; sourceTree = ""; }; - 4A82B7FD1F25691B0063D731 /* Types */ = { + 4A82B7FD1F25691B0063D731 /* Parse Types */ = { isa = PBXGroup; children = ( 4AC3976F1F48778900DEA9D3 /* ACL.swift */, 4AF85BD21F78011100665264 /* ParseError.swift */, 4A82B7F01F254B820063D731 /* File.swift */, 4A82B7ED1F254B820063D731 /* GeoPoint.swift */, + F92B578C24C3F0F300A43E8D /* NoBody.swift */, 4A82B7F11F254B820063D731 /* Pointer.swift */, 4A82B7FE1F256A8F0063D731 /* Query.swift */, ); - path = Types; + path = "Parse Types"; sourceTree = ""; }; 4A99A46A1F2650E200D72A59 /* Mutations */ = { @@ -305,10 +307,9 @@ children = ( 4A82B7EE1F254B820063D731 /* Parse.swift */, 4A2F14901F4A41B900A7A7EF /* Asynchronous.swift */, - 4AC397761F4895A200DEA9D3 /* Objects Protocols */, - 4A82B7FD1F25691B0063D731 /* Types */, - 709075CD24B9829600B95310 /* AnyCodable */, - 4A2F149C1F4A604900A7A7EF /* Encoder */, + 4AC397761F4895A200DEA9D3 /* Objects */, + 4A82B7FD1F25691B0063D731 /* Parse Types */, + 709075CD24B9829600B95310 /* Coding */, 4A99A46A1F2650E200D72A59 /* Mutations */, 4AC397771F4895C000DEA9D3 /* API */, 4AA807491F7930D0008CD551 /* Storage */, @@ -317,16 +318,17 @@ path = ParseSwift; sourceTree = ""; }; - 4AC397761F4895A200DEA9D3 /* Objects Protocols */ = { + 4AC397761F4895A200DEA9D3 /* Objects */ = { isa = PBXGroup; children = ( - 4A82B7EC1F254B820063D731 /* ObjectType.swift */, - 4A82B8001F256B330063D731 /* ObjectType+Query.swift */, - 4A2F14931F4A5E1E00A7A7EF /* ObjectType+Equatable.swift */, - 4A2F14971F4A5F6900A7A7EF /* ObjectType+Batch.swift */, + F927E37B24C3D1FD00F8A143 /* Fetchable.swift */, + F927E37824C3D19900F8A143 /* ParseObject.swift */, + 4A2F14971F4A5F6900A7A7EF /* ParseObject+Batch.swift */, + F92B578924C3F09600A43E8D /* Queryable.swift */, + F92B578624C3F02D00A43E8D /* Saveable.swift */, 4AEBA54E1F265A0D00628B17 /* UserType.swift */, ); - path = "Objects Protocols"; + path = Objects; sourceTree = ""; }; 4AC397771F4895C000DEA9D3 /* API */ = { @@ -349,14 +351,16 @@ path = "ParseSwift-macOS"; sourceTree = ""; }; - 709075CD24B9829600B95310 /* AnyCodable */ = { + 709075CD24B9829600B95310 /* Coding */ = { isa = PBXGroup; children = ( 709075C424B9117400B95310 /* AnyCodable.swift */, 709075C524B9117500B95310 /* AnyDecodable.swift */, 709075C624B9117500B95310 /* AnyEncodable.swift */, + 4A82B7EC1F254B820063D731 /* ObjectType.swift */, + 4A2D8C801F48B3A900EE1FCC /* ParseEncoder.swift */, ); - path = AnyCodable; + path = Coding; sourceTree = ""; }; 7FFF552A2217E729007C3B4E /* AnyCodableTests */ = { @@ -563,7 +567,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if which swiftlint >/dev/null; then\nswiftlint\nelse\necho \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi"; + shellScript = "if which swiftlint >/dev/null; then\nswiftlint autocorrect\nswiftlint\nelse\necho \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; }; 4A6511551F49D544005237DF /* SwiftLint */ = { isa = PBXShellScriptBuildPhase; @@ -577,7 +581,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if which swiftlint >/dev/null; then\nswiftlint\nelse\necho \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi"; + shellScript = "if which swiftlint >/dev/null; then\nswiftlint autocorrect\nswiftlint\nelse\necho \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; }; /* End PBXShellScriptBuildPhase section */ @@ -602,21 +606,24 @@ 4AA8074B1F7930E9008CD551 /* SecureStorage.swift in Sources */, 4A82B7F61F254CCE0063D731 /* Parse.swift in Sources */, 4AEBA54F1F265A0D00628B17 /* UserType.swift in Sources */, + F92B578D24C3F0F300A43E8D /* NoBody.swift in Sources */, + F927E37C24C3D1FD00F8A143 /* Fetchable.swift in Sources */, 4A99A4691F2650CA00D72A59 /* ParseMutationContainer.swift in Sources */, 4AC397701F48778900DEA9D3 /* ACL.swift in Sources */, 4A2D8C811F48B3A900EE1FCC /* ParseEncoder.swift in Sources */, 4A99A46E1F26512100D72A59 /* IncrementOperation.swift in Sources */, - 4A82B8011F256B330063D731 /* ObjectType+Query.swift in Sources */, 4A82B7FF1F256A8F0063D731 /* Query.swift in Sources */, 4AF85BD81F78144900665264 /* URLSession+sync.swift in Sources */, - 4A2F14981F4A5F6900A7A7EF /* ObjectType+Batch.swift in Sources */, + F927E37924C3D19900F8A143 /* ParseObject.swift in Sources */, + 4A2F14981F4A5F6900A7A7EF /* ParseObject+Batch.swift in Sources */, 709075CB24B9117500B95310 /* AnyEncodable.swift in Sources */, 4A82B7F41F254CCE0063D731 /* File.swift in Sources */, 4AF85BD31F78011100665264 /* ParseError.swift in Sources */, 4AF85BDA1F781ED000665264 /* Asynchronous.swift in Sources */, + F92B578724C3F02D00A43E8D /* Saveable.swift in Sources */, 4AA8074E1F7931B7008CD551 /* KeychainStore.swift in Sources */, - 4A2F14941F4A5E1E00A7A7EF /* ObjectType+Equatable.swift in Sources */, 4AC397721F488F9E00DEA9D3 /* BatchUtils.swift in Sources */, + F92B578A24C3F09600A43E8D /* Queryable.swift in Sources */, 4AEBA54D1F26523800628B17 /* DeleteOperation.swift in Sources */, 4AF85BDD1F783B9800665264 /* API+Commands.swift in Sources */, 4A82B7F81F254CCE0063D731 /* Pointer.swift in Sources */, @@ -646,26 +653,29 @@ 4AFDA72B1F26DAE1002AE4FC /* ObjectType.swift in Sources */, 709075C824B9117500B95310 /* AnyCodable.swift in Sources */, 4AFDA7301F26DAE1002AE4FC /* DeleteOperation.swift in Sources */, - 4AFDA7361F26DAE1002AE4FC /* ObjectType+Query.swift in Sources */, 4AFDA7341F26DAE1002AE4FC /* Pointer.swift in Sources */, 4AA8074C1F7930E9008CD551 /* SecureStorage.swift in Sources */, 4A6511501F48E400005237DF /* BatchUtils.swift in Sources */, 4AFDA72A1F26DAE1002AE4FC /* Parse.swift in Sources */, + F92B578E24C3F0F300A43E8D /* NoBody.swift in Sources */, + F927E37D24C3D1FD00F8A143 /* Fetchable.swift in Sources */, 4AFDA7351F26DAE1002AE4FC /* Query.swift in Sources */, 4A2F14991F4A5FB500A7A7EF /* Responses.swift in Sources */, - 4A2F149A1F4A5FBA00A7A7EF /* ObjectType+Equatable.swift in Sources */, 4A65114F1F48E3F3005237DF /* ParseEncoder.swift in Sources */, 4AFDA72E1F26DAE1002AE4FC /* AddOperation.swift in Sources */, 4AFDA7311F26DAE1002AE4FC /* AddUniqueOperation.swift in Sources */, 4AF85BD91F78145C00665264 /* URLSession+sync.swift in Sources */, - 4A2F149B1F4A5FBA00A7A7EF /* ObjectType+Batch.swift in Sources */, + F927E37A24C3D19900F8A143 /* ParseObject.swift in Sources */, + 4A2F149B1F4A5FBA00A7A7EF /* ParseObject+Batch.swift in Sources */, 709075CC24B9117500B95310 /* AnyEncodable.swift in Sources */, 4A6511521F48E406005237DF /* GeoPoint.swift in Sources */, 4AF85BD61F7803C100665264 /* ParseError.swift in Sources */, 4AF85BDB1F781ED100665264 /* Asynchronous.swift in Sources */, + F92B578824C3F02D00A43E8D /* Saveable.swift in Sources */, 4AA8074F1F7931B7008CD551 /* KeychainStore.swift in Sources */, 4AFDA7331F26DAE1002AE4FC /* File.swift in Sources */, 4A6511531F48E410005237DF /* API.swift in Sources */, + F92B578B24C3F09600A43E8D /* Queryable.swift in Sources */, 4AFDA7321F26DAE1002AE4FC /* IncrementOperation.swift in Sources */, 4AF85BDE1F783BB400665264 /* API+Commands.swift in Sources */, 4AFDA72D1F26DAE1002AE4FC /* ParseMutationContainer.swift in Sources */, diff --git a/Sources/ParseSwift/AnyCodable/AnyCodable.swift b/Sources/ParseSwift/Coding/AnyCodable.swift similarity index 100% rename from Sources/ParseSwift/AnyCodable/AnyCodable.swift rename to Sources/ParseSwift/Coding/AnyCodable.swift diff --git a/Sources/ParseSwift/AnyCodable/AnyDecodable.swift b/Sources/ParseSwift/Coding/AnyDecodable.swift similarity index 100% rename from Sources/ParseSwift/AnyCodable/AnyDecodable.swift rename to Sources/ParseSwift/Coding/AnyDecodable.swift diff --git a/Sources/ParseSwift/AnyCodable/AnyEncodable.swift b/Sources/ParseSwift/Coding/AnyEncodable.swift similarity index 100% rename from Sources/ParseSwift/AnyCodable/AnyEncodable.swift rename to Sources/ParseSwift/Coding/AnyEncodable.swift diff --git a/Sources/ParseSwift/Objects Protocols/ObjectType.swift b/Sources/ParseSwift/Coding/ObjectType.swift similarity index 53% rename from Sources/ParseSwift/Objects Protocols/ObjectType.swift rename to Sources/ParseSwift/Coding/ObjectType.swift index aecca686b..8e3763196 100644 --- a/Sources/ParseSwift/Objects Protocols/ObjectType.swift +++ b/Sources/ParseSwift/Coding/ObjectType.swift @@ -8,73 +8,12 @@ import Foundation -public struct NoBody: Codable {} - -public protocol Saving: Codable { - associatedtype SavingType - func save(options: API.Options) throws -> SavingType - func save() throws -> SavingType -} - -extension Saving { - public func save() throws -> SavingType { - return try save(options: []) - } -} - -public protocol Fetching: Codable { - associatedtype FetchingType - func fetch(options: API.Options) throws -> FetchingType - func fetch() throws -> FetchingType -} - -extension Fetching { - public func fetch() throws -> FetchingType { - return try fetch(options: []) - } -} - -public protocol ObjectType: Fetching, Saving, CustomDebugStringConvertible, Equatable { - static var className: String { get } - var objectId: String? { get set } - var createdAt: Date? { get set } - var updatedAt: Date? { get set } - var ACL: ACL? { get set } -} - internal extension ObjectType { func getEncoder() -> ParseEncoder { return getParseEncoder() } } -extension ObjectType { - // Parse ClassName inference - public static var className: String { - let classType = "\(type(of: self))" - return classType.components(separatedBy: ".").first! // strip .Type - } - public var className: String { - return Self.className - } -} - -extension ObjectType { - public var debugDescription: String { - guard let descriptionData = try? getJSONEncoder().encode(self), - let descriptionString = String(data: descriptionData, encoding: .utf8) else { - return "\(className) ()" - } - return "\(className) (\(descriptionString))" - } -} - -public extension ObjectType { - func toPointer() -> Pointer { - return Pointer(self) - } -} - enum DateEncodingKeys: String, CodingKey { case iso case type = "__type" @@ -159,45 +98,3 @@ func getDecoder() -> JSONDecoder { encoder.dateDecodingStrategy = dateDecodingStrategy return encoder } - -public extension ObjectType { - func save(options: API.Options) throws -> Self { - return try saveCommand().execute(options: options) - } - - func fetch(options: API.Options) throws -> Self { - return try fetchCommand().execute(options: options) - } - - internal func saveCommand() -> API.Command { - return API.Command.saveCommand(self) - } - - internal func fetchCommand() throws -> API.Command { - return try API.Command.fetchCommand(self) - } -} - -extension ObjectType { - var endpoint: API.Endpoint { - if let objectId = objectId { - return .object(className: className, objectId: objectId) - } - return .objects(className: className) - } - - var isSaved: Bool { - return objectId != nil - } -} - -public struct FindResult: Decodable where T: ObjectType { - let results: [T] - let count: Int? -} - -public extension ObjectType { - var mutationContainer: ParseMutationContainer { - return ParseMutationContainer(target: self) - } -} diff --git a/Sources/ParseSwift/Encoder/ParseEncoder.swift b/Sources/ParseSwift/Coding/ParseEncoder.swift similarity index 100% rename from Sources/ParseSwift/Encoder/ParseEncoder.swift rename to Sources/ParseSwift/Coding/ParseEncoder.swift diff --git a/Sources/ParseSwift/Objects Protocols/ObjectType+Equatable.swift b/Sources/ParseSwift/Objects Protocols/ObjectType+Equatable.swift deleted file mode 100644 index 776096a42..000000000 --- a/Sources/ParseSwift/Objects Protocols/ObjectType+Equatable.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// ObjectType+Equatable.swift -// ParseSwift -// -// Created by Florent Vilmart on 17-08-20. -// Copyright © 2017 Parse. All rights reserved. -// - -import Foundation - -public func == (lhs: T?, rhs: T?) -> Bool where T: ObjectType { - guard let lhs = lhs, let rhs = rhs else { return false } - return lhs == rhs -} - -public func == (lhs: T, rhs: T) -> Bool where T: ObjectType { - return lhs.className == rhs.className && rhs.objectId == lhs.objectId -} diff --git a/Sources/ParseSwift/Objects Protocols/ObjectType+Query.swift b/Sources/ParseSwift/Objects Protocols/ObjectType+Query.swift deleted file mode 100644 index c963094d3..000000000 --- a/Sources/ParseSwift/Objects Protocols/ObjectType+Query.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// Object+Query.swift -// Parse -// -// Created by Florent Vilmart on 17-07-23. -// Copyright © 2017 Parse. All rights reserved. -// - -import Foundation - -public extension ObjectType { - static func find() throws -> [Self] { - return try query().find() - } - - static func query() -> Query { - return Query() - } - - static func query(_ constraints: QueryConstraint...) -> Query { - return Query(constraints) - } -} diff --git a/Sources/ParseSwift/Objects/Fetchable.swift b/Sources/ParseSwift/Objects/Fetchable.swift new file mode 100644 index 000000000..34e868304 --- /dev/null +++ b/Sources/ParseSwift/Objects/Fetchable.swift @@ -0,0 +1,20 @@ +// +// Fetchable.swift +// ParseSwift +// +// Created by Pranjal Satija on 7/18/20. +// Copyright © 2020 Parse. All rights reserved. +// + +public protocol Fetching: Codable { + associatedtype FetchingType + + func fetch(options: API.Options) throws -> FetchingType + func fetch() throws -> FetchingType +} + +extension Fetching { + public func fetch() throws -> FetchingType { + return try fetch(options: []) + } +} diff --git a/Sources/ParseSwift/Objects Protocols/ObjectType+Batch.swift b/Sources/ParseSwift/Objects/ParseObject+Batch.swift similarity index 100% rename from Sources/ParseSwift/Objects Protocols/ObjectType+Batch.swift rename to Sources/ParseSwift/Objects/ParseObject+Batch.swift diff --git a/Sources/ParseSwift/Objects/ParseObject.swift b/Sources/ParseSwift/Objects/ParseObject.swift new file mode 100644 index 000000000..39a2b9940 --- /dev/null +++ b/Sources/ParseSwift/Objects/ParseObject.swift @@ -0,0 +1,107 @@ +// +// ParseObject.swift +// ParseSwift +// +// Created by Pranjal Satija on 7/18/20. +// Copyright © 2020 Parse. All rights reserved. +// + +import Foundation + +public protocol ObjectType: Fetching, Saving, CustomDebugStringConvertible, Equatable { + static var className: String { get } + + var objectId: String? { get set } + var createdAt: Date? { get set } + var updatedAt: Date? { get set } + var ACL: ACL? { get set } +} + +extension ObjectType { + public static var className: String { + let classType = "\(type(of: self))" + return classType.components(separatedBy: ".").first! // strip .Type + } + + public var className: String { + return Self.className + } +} + +extension ObjectType { + public var debugDescription: String { + guard let descriptionData = try? getJSONEncoder().encode(self), + let descriptionString = String(data: descriptionData, encoding: .utf8) else { + return "\(className) ()" + } + + return "\(className) (\(descriptionString))" + } +} + +public extension ObjectType { + func toPointer() -> Pointer { + return Pointer(self) + } +} + +public extension ObjectType { + func save(options: API.Options) throws -> Self { + return try saveCommand().execute(options: options) + } + + func fetch(options: API.Options) throws -> Self { + return try fetchCommand().execute(options: options) + } + + internal func saveCommand() -> API.Command { + return API.Command.saveCommand(self) + } + + internal func fetchCommand() throws -> API.Command { + return try API.Command.fetchCommand(self) + } +} + +public extension ObjectType { + static func find() throws -> [Self] { + return try query().find() + } + + static func query() -> Query { + return Query() + } + + static func query(_ constraints: QueryConstraint...) -> Query { + return Query(constraints) + } +} + +extension ObjectType { + var endpoint: API.Endpoint { + if let objectId = objectId { + return .object(className: className, objectId: objectId) + } + + return .objects(className: className) + } + + var isSaved: Bool { + return objectId != nil + } +} + +public extension ObjectType { + var mutationContainer: ParseMutationContainer { + return ParseMutationContainer(target: self) + } +} + +public func == (lhs: T?, rhs: T?) -> Bool where T: ObjectType { + guard let lhs = lhs, let rhs = rhs else { return false } + return lhs == rhs +} + +public func == (lhs: T, rhs: T) -> Bool where T: ObjectType { + return lhs.className == rhs.className && rhs.objectId == lhs.objectId +} diff --git a/Sources/ParseSwift/Objects/Queryable.swift b/Sources/ParseSwift/Objects/Queryable.swift new file mode 100644 index 000000000..5a37ad0f3 --- /dev/null +++ b/Sources/ParseSwift/Objects/Queryable.swift @@ -0,0 +1,29 @@ +// +// Queryable.swift +// ParseSwift +// +// Created by Pranjal Satija on 7/18/20. +// Copyright © 2020 Parse. All rights reserved. +// + +public protocol Querying { + associatedtype ResultType + + func find(options: API.Options) throws -> [ResultType] + func first(options: API.Options) throws -> ResultType? + func count(options: API.Options) throws -> Int +} + +extension Querying { + func find() throws -> [ResultType] { + return try find(options: []) + } + + func first() throws -> ResultType? { + return try first(options: []) + } + + func count() throws -> Int { + return try count(options: []) + } +} diff --git a/Sources/ParseSwift/Objects/Saveable.swift b/Sources/ParseSwift/Objects/Saveable.swift new file mode 100644 index 000000000..3e46f9d87 --- /dev/null +++ b/Sources/ParseSwift/Objects/Saveable.swift @@ -0,0 +1,20 @@ +// +// Saveable.swift +// ParseSwift +// +// Created by Pranjal Satija on 7/18/20. +// Copyright © 2020 Parse. All rights reserved. +// + +public protocol Saving: Codable { + associatedtype SavingType + + func save(options: API.Options) throws -> SavingType + func save() throws -> SavingType +} + +extension Saving { + public func save() throws -> SavingType { + return try save(options: []) + } +} diff --git a/Sources/ParseSwift/Objects Protocols/UserType.swift b/Sources/ParseSwift/Objects/UserType.swift similarity index 99% rename from Sources/ParseSwift/Objects Protocols/UserType.swift rename to Sources/ParseSwift/Objects/UserType.swift index bfe1e7588..0525a8496 100644 --- a/Sources/ParseSwift/Objects Protocols/UserType.swift +++ b/Sources/ParseSwift/Objects/UserType.swift @@ -18,6 +18,7 @@ public extension UserType { currentUser.objectId == self.objectId { return CurrentUserInfo.currentSessionToken } + return nil } @@ -57,6 +58,7 @@ private extension UserType { "username": username, "password": password ] + return API.Command(method: .GET, path: .login, params: params) { (data) -> Self in @@ -70,6 +72,7 @@ private extension UserType { private static func signupCommand(username: String, password: String) -> API.Command { + let body = SignupBody(username: username, password: password) return API.Command(method: .POST, path: .signup, body: body) { (data) -> Self in let response = try getDecoder().decode(LoginSignupResponse.self, from: data) diff --git a/Sources/ParseSwift/Types/ACL.swift b/Sources/ParseSwift/Parse Types/ACL.swift similarity index 100% rename from Sources/ParseSwift/Types/ACL.swift rename to Sources/ParseSwift/Parse Types/ACL.swift diff --git a/Sources/ParseSwift/Types/File.swift b/Sources/ParseSwift/Parse Types/File.swift similarity index 100% rename from Sources/ParseSwift/Types/File.swift rename to Sources/ParseSwift/Parse Types/File.swift diff --git a/Sources/ParseSwift/Types/GeoPoint.swift b/Sources/ParseSwift/Parse Types/GeoPoint.swift similarity index 100% rename from Sources/ParseSwift/Types/GeoPoint.swift rename to Sources/ParseSwift/Parse Types/GeoPoint.swift diff --git a/Sources/ParseSwift/Parse Types/NoBody.swift b/Sources/ParseSwift/Parse Types/NoBody.swift new file mode 100644 index 000000000..cf85ad46d --- /dev/null +++ b/Sources/ParseSwift/Parse Types/NoBody.swift @@ -0,0 +1,9 @@ +// +// NoBody.swift +// ParseSwift +// +// Created by Pranjal Satija on 7/18/20. +// Copyright © 2020 Parse. All rights reserved. +// + +public struct NoBody: Codable {} diff --git a/Sources/ParseSwift/Types/ParseError.swift b/Sources/ParseSwift/Parse Types/ParseError.swift similarity index 100% rename from Sources/ParseSwift/Types/ParseError.swift rename to Sources/ParseSwift/Parse Types/ParseError.swift diff --git a/Sources/ParseSwift/Types/Pointer.swift b/Sources/ParseSwift/Parse Types/Pointer.swift similarity index 100% rename from Sources/ParseSwift/Types/Pointer.swift rename to Sources/ParseSwift/Parse Types/Pointer.swift diff --git a/Sources/ParseSwift/Types/Query.swift b/Sources/ParseSwift/Parse Types/Query.swift similarity index 93% rename from Sources/ParseSwift/Types/Query.swift rename to Sources/ParseSwift/Parse Types/Query.swift index 8a952379c..793961691 100644 --- a/Sources/ParseSwift/Types/Query.swift +++ b/Sources/ParseSwift/Parse Types/Query.swift @@ -7,23 +7,10 @@ // import Foundation -public protocol Querying { - associatedtype ResultType - func find(options: API.Options) throws -> [ResultType] - func first(options: API.Options) throws -> ResultType? - func count(options: API.Options) throws -> Int -} -extension Querying { - func find() throws -> [ResultType] { - return try find(options: []) - } - func first() throws -> ResultType? { - return try first(options: []) - } - func count() throws -> Int { - return try count(options: []) - } +public struct FindResult: Decodable where T: ObjectType { + let results: [T] + let count: Int? } public struct QueryConstraint: Encodable { From 77c84dc5328bba7ef43c2a9d8e111d6768f0939c Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Sun, 19 Jul 2020 00:43:50 -0400 Subject: [PATCH 02/30] rename things --- ParseSwift.xcodeproj/project.pbxproj | 30 +++++++--------- Sources/ParseSwift/API/API+Commands.swift | 10 +++--- Sources/ParseSwift/API/BatchUtils.swift | 6 ++-- Sources/ParseSwift/API/Responses.swift | 4 +-- Sources/ParseSwift/Asynchronous.swift | 10 +++--- .../{ObjectType.swift => Miscellaneous.swift} | 2 +- .../ParseMutationContainer.swift | 3 +- Sources/ParseSwift/Objects/Fetchable.swift | 4 +-- .../Objects/ParseObject+Batch.swift | 24 ------------- Sources/ParseSwift/Objects/ParseObject.swift | 35 +++++++++++++------ .../{UserType.swift => ParseUser.swift} | 8 ++--- Sources/ParseSwift/Objects/Queryable.swift | 4 +-- Sources/ParseSwift/Objects/Saveable.swift | 4 +-- Sources/ParseSwift/Parse Types/File.swift | 2 +- Sources/ParseSwift/Parse Types/Pointer.swift | 4 +-- Sources/ParseSwift/Parse Types/Query.swift | 8 ++--- 16 files changed, 72 insertions(+), 86 deletions(-) rename Sources/ParseSwift/Coding/{ObjectType.swift => Miscellaneous.swift} (98%) delete mode 100644 Sources/ParseSwift/Objects/ParseObject+Batch.swift rename Sources/ParseSwift/Objects/{UserType.swift => ParseUser.swift} (96%) diff --git a/ParseSwift.xcodeproj/project.pbxproj b/ParseSwift.xcodeproj/project.pbxproj index 4506cc744..cd578686b 100644 --- a/ParseSwift.xcodeproj/project.pbxproj +++ b/ParseSwift.xcodeproj/project.pbxproj @@ -9,9 +9,7 @@ /* Begin PBXBuildFile section */ 4A2D8C811F48B3A900EE1FCC /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2D8C801F48B3A900EE1FCC /* ParseEncoder.swift */; }; 4A2F14961F4A5F2900A7A7EF /* Responses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14951F4A5F2900A7A7EF /* Responses.swift */; }; - 4A2F14981F4A5F6900A7A7EF /* ParseObject+Batch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14971F4A5F6900A7A7EF /* ParseObject+Batch.swift */; }; 4A2F14991F4A5FB500A7A7EF /* Responses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14951F4A5F2900A7A7EF /* Responses.swift */; }; - 4A2F149B1F4A5FBA00A7A7EF /* ParseObject+Batch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14971F4A5F6900A7A7EF /* ParseObject+Batch.swift */; }; 4A65114F1F48E3F3005237DF /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2D8C801F48B3A900EE1FCC /* ParseEncoder.swift */; }; 4A6511501F48E400005237DF /* BatchUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC397711F488F9E00DEA9D3 /* BatchUtils.swift */; }; 4A6511511F48E406005237DF /* ACL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC3976F1F48778900DEA9D3 /* ACL.swift */; }; @@ -20,7 +18,7 @@ 4A82B7F41F254CCE0063D731 /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7F01F254B820063D731 /* File.swift */; }; 4A82B7F51F254CCE0063D731 /* GeoPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7ED1F254B820063D731 /* GeoPoint.swift */; }; 4A82B7F61F254CCE0063D731 /* Parse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EE1F254B820063D731 /* Parse.swift */; }; - 4A82B7F71F254CCE0063D731 /* ObjectType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EC1F254B820063D731 /* ObjectType.swift */; }; + 4A82B7F71F254CCE0063D731 /* Miscellaneous.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EC1F254B820063D731 /* Miscellaneous.swift */; }; 4A82B7F81F254CCE0063D731 /* Pointer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7F11F254B820063D731 /* Pointer.swift */; }; 4A82B7FF1F256A8F0063D731 /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7FE1F256A8F0063D731 /* Query.swift */; }; 4A99A4691F2650CA00D72A59 /* ParseMutationContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A99A4681F2650CA00D72A59 /* ParseMutationContainer.swift */; }; @@ -44,7 +42,7 @@ 4AEBA5491F26519B00628B17 /* AddOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA5481F26519B00628B17 /* AddOperation.swift */; }; 4AEBA54B1F2651D900628B17 /* RemoveOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA54A1F2651D900628B17 /* RemoveOperation.swift */; }; 4AEBA54D1F26523800628B17 /* DeleteOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA54C1F26523800628B17 /* DeleteOperation.swift */; }; - 4AEBA54F1F265A0D00628B17 /* UserType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA54E1F265A0D00628B17 /* UserType.swift */; }; + 4AEBA54F1F265A0D00628B17 /* ParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA54E1F265A0D00628B17 /* ParseUser.swift */; }; 4AF85BD31F78011100665264 /* ParseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AF85BD21F78011100665264 /* ParseError.swift */; }; 4AF85BD61F7803C100665264 /* ParseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AF85BD21F78011100665264 /* ParseError.swift */; }; 4AF85BD81F78144900665264 /* URLSession+sync.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AF85BD71F78144900665264 /* URLSession+sync.swift */; }; @@ -54,8 +52,8 @@ 4AF85BDD1F783B9800665264 /* API+Commands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AF85BDC1F783B9800665264 /* API+Commands.swift */; }; 4AF85BDE1F783BB400665264 /* API+Commands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AF85BDC1F783B9800665264 /* API+Commands.swift */; }; 4AFDA72A1F26DAE1002AE4FC /* Parse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EE1F254B820063D731 /* Parse.swift */; }; - 4AFDA72B1F26DAE1002AE4FC /* ObjectType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EC1F254B820063D731 /* ObjectType.swift */; }; - 4AFDA72C1F26DAE1002AE4FC /* UserType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA54E1F265A0D00628B17 /* UserType.swift */; }; + 4AFDA72B1F26DAE1002AE4FC /* Miscellaneous.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EC1F254B820063D731 /* Miscellaneous.swift */; }; + 4AFDA72C1F26DAE1002AE4FC /* ParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA54E1F265A0D00628B17 /* ParseUser.swift */; }; 4AFDA72D1F26DAE1002AE4FC /* ParseMutationContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A99A4681F2650CA00D72A59 /* ParseMutationContainer.swift */; }; 4AFDA72E1F26DAE1002AE4FC /* AddOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA5481F26519B00628B17 /* AddOperation.swift */; }; 4AFDA72F1F26DAE1002AE4FC /* RemoveOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA54A1F2651D900628B17 /* RemoveOperation.swift */; }; @@ -109,8 +107,7 @@ 4A2D8C801F48B3A900EE1FCC /* ParseEncoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseEncoder.swift; sourceTree = ""; }; 4A2F14901F4A41B900A7A7EF /* Asynchronous.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Asynchronous.swift; sourceTree = ""; }; 4A2F14951F4A5F2900A7A7EF /* Responses.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Responses.swift; sourceTree = ""; }; - 4A2F14971F4A5F6900A7A7EF /* ParseObject+Batch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParseObject+Batch.swift"; sourceTree = ""; }; - 4A82B7EC1F254B820063D731 /* ObjectType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObjectType.swift; sourceTree = ""; }; + 4A82B7EC1F254B820063D731 /* Miscellaneous.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Miscellaneous.swift; sourceTree = ""; }; 4A82B7ED1F254B820063D731 /* GeoPoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoPoint.swift; sourceTree = ""; }; 4A82B7EE1F254B820063D731 /* Parse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Parse.swift; sourceTree = ""; }; 4A82B7F01F254B820063D731 /* File.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = File.swift; sourceTree = ""; }; @@ -141,7 +138,7 @@ 4AEBA5481F26519B00628B17 /* AddOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddOperation.swift; sourceTree = ""; }; 4AEBA54A1F2651D900628B17 /* RemoveOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveOperation.swift; sourceTree = ""; }; 4AEBA54C1F26523800628B17 /* DeleteOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteOperation.swift; sourceTree = ""; }; - 4AEBA54E1F265A0D00628B17 /* UserType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserType.swift; sourceTree = ""; }; + 4AEBA54E1F265A0D00628B17 /* ParseUser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseUser.swift; sourceTree = ""; }; 4AF85BD21F78011100665264 /* ParseError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseError.swift; sourceTree = ""; }; 4AF85BD71F78144900665264 /* URLSession+sync.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URLSession+sync.swift"; sourceTree = ""; }; 4AF85BDC1F783B9800665264 /* API+Commands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "API+Commands.swift"; sourceTree = ""; }; @@ -323,10 +320,9 @@ children = ( F927E37B24C3D1FD00F8A143 /* Fetchable.swift */, F927E37824C3D19900F8A143 /* ParseObject.swift */, - 4A2F14971F4A5F6900A7A7EF /* ParseObject+Batch.swift */, F92B578924C3F09600A43E8D /* Queryable.swift */, F92B578624C3F02D00A43E8D /* Saveable.swift */, - 4AEBA54E1F265A0D00628B17 /* UserType.swift */, + 4AEBA54E1F265A0D00628B17 /* ParseUser.swift */, ); path = Objects; sourceTree = ""; @@ -357,7 +353,7 @@ 709075C424B9117400B95310 /* AnyCodable.swift */, 709075C524B9117500B95310 /* AnyDecodable.swift */, 709075C624B9117500B95310 /* AnyEncodable.swift */, - 4A82B7EC1F254B820063D731 /* ObjectType.swift */, + 4A82B7EC1F254B820063D731 /* Miscellaneous.swift */, 4A2D8C801F48B3A900EE1FCC /* ParseEncoder.swift */, ); path = Coding; @@ -601,11 +597,11 @@ 4A2F14961F4A5F2900A7A7EF /* Responses.swift in Sources */, 709075C724B9117500B95310 /* AnyCodable.swift in Sources */, 4AC397741F488FF900DEA9D3 /* API.swift in Sources */, - 4A82B7F71F254CCE0063D731 /* ObjectType.swift in Sources */, + 4A82B7F71F254CCE0063D731 /* Miscellaneous.swift in Sources */, 4A82B7F51F254CCE0063D731 /* GeoPoint.swift in Sources */, 4AA8074B1F7930E9008CD551 /* SecureStorage.swift in Sources */, 4A82B7F61F254CCE0063D731 /* Parse.swift in Sources */, - 4AEBA54F1F265A0D00628B17 /* UserType.swift in Sources */, + 4AEBA54F1F265A0D00628B17 /* ParseUser.swift in Sources */, F92B578D24C3F0F300A43E8D /* NoBody.swift in Sources */, F927E37C24C3D1FD00F8A143 /* Fetchable.swift in Sources */, 4A99A4691F2650CA00D72A59 /* ParseMutationContainer.swift in Sources */, @@ -615,7 +611,6 @@ 4A82B7FF1F256A8F0063D731 /* Query.swift in Sources */, 4AF85BD81F78144900665264 /* URLSession+sync.swift in Sources */, F927E37924C3D19900F8A143 /* ParseObject.swift in Sources */, - 4A2F14981F4A5F6900A7A7EF /* ParseObject+Batch.swift in Sources */, 709075CB24B9117500B95310 /* AnyEncodable.swift in Sources */, 4A82B7F41F254CCE0063D731 /* File.swift in Sources */, 4AF85BD31F78011100665264 /* ParseError.swift in Sources */, @@ -650,7 +645,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 4AFDA72B1F26DAE1002AE4FC /* ObjectType.swift in Sources */, + 4AFDA72B1F26DAE1002AE4FC /* Miscellaneous.swift in Sources */, 709075C824B9117500B95310 /* AnyCodable.swift in Sources */, 4AFDA7301F26DAE1002AE4FC /* DeleteOperation.swift in Sources */, 4AFDA7341F26DAE1002AE4FC /* Pointer.swift in Sources */, @@ -666,7 +661,6 @@ 4AFDA7311F26DAE1002AE4FC /* AddUniqueOperation.swift in Sources */, 4AF85BD91F78145C00665264 /* URLSession+sync.swift in Sources */, F927E37A24C3D19900F8A143 /* ParseObject.swift in Sources */, - 4A2F149B1F4A5FBA00A7A7EF /* ParseObject+Batch.swift in Sources */, 709075CC24B9117500B95310 /* AnyEncodable.swift in Sources */, 4A6511521F48E406005237DF /* GeoPoint.swift in Sources */, 4AF85BD61F7803C100665264 /* ParseError.swift in Sources */, @@ -680,7 +674,7 @@ 4AF85BDE1F783BB400665264 /* API+Commands.swift in Sources */, 4AFDA72D1F26DAE1002AE4FC /* ParseMutationContainer.swift in Sources */, 709075CA24B9117500B95310 /* AnyDecodable.swift in Sources */, - 4AFDA72C1F26DAE1002AE4FC /* UserType.swift in Sources */, + 4AFDA72C1F26DAE1002AE4FC /* ParseUser.swift in Sources */, 4A6511511F48E406005237DF /* ACL.swift in Sources */, 4AFDA72F1F26DAE1002AE4FC /* RemoveOperation.swift in Sources */, ); diff --git a/Sources/ParseSwift/API/API+Commands.swift b/Sources/ParseSwift/API/API+Commands.swift index 60e79a02a..c17c4f82e 100644 --- a/Sources/ParseSwift/API/API+Commands.swift +++ b/Sources/ParseSwift/API/API+Commands.swift @@ -63,7 +63,7 @@ internal extension API { internal extension API.Command { // MARK: Saving - static func saveCommand(_ object: T) -> API.Command where T: ObjectType { + static func saveCommand(_ object: T) -> API.Command where T: ParseObject { if object.isSaved { return updateCommand(object) } @@ -71,7 +71,7 @@ internal extension API.Command { } // MARK: Saving - private - private static func createCommand(_ object: T) -> API.Command where T: ObjectType { + private static func createCommand(_ object: T) -> API.Command where T: ParseObject { let mapper = { (data) -> T in try getDecoder().decode(SaveResponse.self, from: data).apply(object) } @@ -81,7 +81,7 @@ internal extension API.Command { mapper: mapper) } - private static func updateCommand(_ object: T) -> API.Command where T: ObjectType { + private static func updateCommand(_ object: T) -> API.Command where T: ParseObject { let mapper = { (data: Data) -> T in try getDecoder().decode(UpdateResponse.self, from: data).apply(object) } @@ -92,7 +92,7 @@ internal extension API.Command { } // MARK: Fetching - static func fetchCommand(_ object: T) throws -> API.Command where T: ObjectType { + static func fetchCommand(_ object: T) throws -> API.Command where T: ParseObject { guard object.isSaved else { throw ParseError(code: .unknownError, message: "Cannot Fetch an object without id") } @@ -103,7 +103,7 @@ internal extension API.Command { } } -extension API.Command where T: ObjectType { +extension API.Command where T: ParseObject { internal var data: Data? { guard let body = body else { return nil } diff --git a/Sources/ParseSwift/API/BatchUtils.swift b/Sources/ParseSwift/API/BatchUtils.swift index 76208b350..b90c1345d 100644 --- a/Sources/ParseSwift/API/BatchUtils.swift +++ b/Sources/ParseSwift/API/BatchUtils.swift @@ -8,10 +8,10 @@ import Foundation -typealias ParseObjectBatchCommand = BatchCommand where T: ObjectType +typealias ParseObjectBatchCommand = BatchCommand where T: ParseObject typealias ParseObjectBatchResponse = [(T, ParseError?)] // swiftlint:disable line_length -typealias RESTBatchCommandType = API.Command, ParseObjectBatchResponse> where T: ObjectType +typealias RESTBatchCommandType = API.Command, ParseObjectBatchResponse> where T: ParseObject // swiftlint:enable line_length public struct BatchCommand: Encodable where T: Encodable { @@ -46,7 +46,7 @@ struct SaveOrUpdateResponse: Decodable { return UpdateResponse(updatedAt: updatedAt) } - func apply(_ object: T) -> T where T: ObjectType { + func apply(_ object: T) -> T where T: ParseObject { if isCreate { return asSaveResponse().apply(object) } else { diff --git a/Sources/ParseSwift/API/Responses.swift b/Sources/ParseSwift/API/Responses.swift index 567724438..d2f28aafd 100644 --- a/Sources/ParseSwift/API/Responses.swift +++ b/Sources/ParseSwift/API/Responses.swift @@ -15,7 +15,7 @@ internal struct SaveResponse: Decodable { return createdAt } - func apply(_ object: T) -> T where T: ObjectType { + func apply(_ object: T) -> T where T: ParseObject { var object = object object.objectId = objectId object.createdAt = createdAt @@ -27,7 +27,7 @@ internal struct SaveResponse: Decodable { internal struct UpdateResponse: Decodable { var updatedAt: Date - func apply(_ object: T) -> T where T: ObjectType { + func apply(_ object: T) -> T where T: ParseObject { var object = object object.updatedAt = updatedAt return object diff --git a/Sources/ParseSwift/Asynchronous.swift b/Sources/ParseSwift/Asynchronous.swift index cfcf8aa8a..9698c69b3 100644 --- a/Sources/ParseSwift/Asynchronous.swift +++ b/Sources/ParseSwift/Asynchronous.swift @@ -22,19 +22,19 @@ private func runAsync(options: API.Options, } } -extension Saving { +extension Saveable { public func save(options: API.Options = [], callback: @escaping (Self.SavingType?, Error?) -> Void) { runAsync(options: options, function: self.save, callback: callback) } } -extension Fetching { +extension Fetchable { public func fetch(options: API.Options = [], callback: @escaping (Self.FetchingType?, Error?) -> Void) { runAsync(options: options, function: self.fetch, callback: callback) } } -extension Querying { +extension Queryable { public func find(options: API.Options = [], callback: @escaping ([ResultType]?, Error?) -> Void) { runAsync(options: options, function: self.find, callback: callback) } @@ -46,7 +46,7 @@ extension Querying { } } -public extension ObjectType { +public extension ParseObject { static func saveAll(options: API.Options = [], _ objects: Self..., callback: @escaping ([(Self, ParseError?)]?, Error?) -> Void) { @@ -54,7 +54,7 @@ public extension ObjectType { } } -public extension Sequence where Element: ObjectType { +public extension Sequence where Element: ParseObject { func saveAll(options: API.Options = [], callback: @escaping ([(Element, ParseError?)]?, Error?) -> Void) { runAsync(options: options, function: self.saveAll, callback: callback) diff --git a/Sources/ParseSwift/Coding/ObjectType.swift b/Sources/ParseSwift/Coding/Miscellaneous.swift similarity index 98% rename from Sources/ParseSwift/Coding/ObjectType.swift rename to Sources/ParseSwift/Coding/Miscellaneous.swift index 8e3763196..632d45c44 100644 --- a/Sources/ParseSwift/Coding/ObjectType.swift +++ b/Sources/ParseSwift/Coding/Miscellaneous.swift @@ -8,7 +8,7 @@ import Foundation -internal extension ObjectType { +internal extension ParseObject { func getEncoder() -> ParseEncoder { return getParseEncoder() } diff --git a/Sources/ParseSwift/MutationOperations/ParseMutationContainer.swift b/Sources/ParseSwift/MutationOperations/ParseMutationContainer.swift index be60e0eab..02e7bb25c 100644 --- a/Sources/ParseSwift/MutationOperations/ParseMutationContainer.swift +++ b/Sources/ParseSwift/MutationOperations/ParseMutationContainer.swift @@ -8,8 +8,9 @@ import Foundation -public struct ParseMutationContainer: Encodable where T: ObjectType { +public struct ParseMutationContainer: Encodable where T: ParseObject { typealias ObjectType = T + var target: T private var operations = [String: Encodable]() diff --git a/Sources/ParseSwift/Objects/Fetchable.swift b/Sources/ParseSwift/Objects/Fetchable.swift index 34e868304..f51911b69 100644 --- a/Sources/ParseSwift/Objects/Fetchable.swift +++ b/Sources/ParseSwift/Objects/Fetchable.swift @@ -6,14 +6,14 @@ // Copyright © 2020 Parse. All rights reserved. // -public protocol Fetching: Codable { +public protocol Fetchable: Codable { associatedtype FetchingType func fetch(options: API.Options) throws -> FetchingType func fetch() throws -> FetchingType } -extension Fetching { +extension Fetchable { public func fetch() throws -> FetchingType { return try fetch(options: []) } diff --git a/Sources/ParseSwift/Objects/ParseObject+Batch.swift b/Sources/ParseSwift/Objects/ParseObject+Batch.swift deleted file mode 100644 index 8b2823ecc..000000000 --- a/Sources/ParseSwift/Objects/ParseObject+Batch.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// ObjectType+Batch.swift -// ParseSwift -// -// Created by Florent Vilmart on 17-08-20. -// Copyright © 2017 Parse. All rights reserved. -// - -import Foundation - -public extension ObjectType { - static func saveAll(_ objects: Self...) throws -> [(Self, ParseError?)] { - return try objects.saveAll() - } -} - -extension Sequence where Element: ObjectType { - public func saveAll(options: API.Options = []) throws -> [(Self.Element, ParseError?)] { - let commands = map { $0.saveCommand() } - return try API.Command - .batch(commands: commands) - .execute(options: options) - } -} diff --git a/Sources/ParseSwift/Objects/ParseObject.swift b/Sources/ParseSwift/Objects/ParseObject.swift index 39a2b9940..84fbfe03f 100644 --- a/Sources/ParseSwift/Objects/ParseObject.swift +++ b/Sources/ParseSwift/Objects/ParseObject.swift @@ -8,7 +8,7 @@ import Foundation -public protocol ObjectType: Fetching, Saving, CustomDebugStringConvertible, Equatable { +public protocol ParseObject: Fetchable, Saveable, CustomDebugStringConvertible, Equatable { static var className: String { get } var objectId: String? { get set } @@ -17,7 +17,7 @@ public protocol ObjectType: Fetching, Saving, CustomDebugStringConvertible, Equa var ACL: ACL? { get set } } -extension ObjectType { +extension ParseObject { public static var className: String { let classType = "\(type(of: self))" return classType.components(separatedBy: ".").first! // strip .Type @@ -28,7 +28,7 @@ extension ObjectType { } } -extension ObjectType { +extension ParseObject { public var debugDescription: String { guard let descriptionData = try? getJSONEncoder().encode(self), let descriptionString = String(data: descriptionData, encoding: .utf8) else { @@ -39,13 +39,13 @@ extension ObjectType { } } -public extension ObjectType { +public extension ParseObject { func toPointer() -> Pointer { return Pointer(self) } } -public extension ObjectType { +public extension ParseObject { func save(options: API.Options) throws -> Self { return try saveCommand().execute(options: options) } @@ -63,7 +63,7 @@ public extension ObjectType { } } -public extension ObjectType { +public extension ParseObject { static func find() throws -> [Self] { return try query().find() } @@ -77,7 +77,7 @@ public extension ObjectType { } } -extension ObjectType { +extension ParseObject { var endpoint: API.Endpoint { if let objectId = objectId { return .object(className: className, objectId: objectId) @@ -91,17 +91,32 @@ extension ObjectType { } } -public extension ObjectType { +public extension ParseObject { var mutationContainer: ParseMutationContainer { return ParseMutationContainer(target: self) } } -public func == (lhs: T?, rhs: T?) -> Bool where T: ObjectType { +public func == (lhs: T?, rhs: T?) -> Bool where T: ParseObject { guard let lhs = lhs, let rhs = rhs else { return false } return lhs == rhs } -public func == (lhs: T, rhs: T) -> Bool where T: ObjectType { +public func == (lhs: T, rhs: T) -> Bool where T: ParseObject { return lhs.className == rhs.className && rhs.objectId == lhs.objectId } + +public extension ParseObject { + static func saveAll(_ objects: Self...) throws -> [(Self, ParseError?)] { + return try objects.saveAll() + } +} + +extension Sequence where Element: ParseObject { + public func saveAll(options: API.Options = []) throws -> [(Self.Element, ParseError?)] { + let commands = map { $0.saveCommand() } + return try API.Command + .batch(commands: commands) + .execute(options: options) + } +} diff --git a/Sources/ParseSwift/Objects/UserType.swift b/Sources/ParseSwift/Objects/ParseUser.swift similarity index 96% rename from Sources/ParseSwift/Objects/UserType.swift rename to Sources/ParseSwift/Objects/ParseUser.swift index 0525a8496..72cb6da2b 100644 --- a/Sources/ParseSwift/Objects/UserType.swift +++ b/Sources/ParseSwift/Objects/ParseUser.swift @@ -5,13 +5,13 @@ internal struct CurrentUserInfo { static var currentSessionToken: String? } -public protocol UserType: ObjectType { +public protocol ParseUser: ParseObject { var username: String? { get set } var email: String? { get set } var password: String? { get set } } -public extension UserType { +public extension ParseUser { var sessionToken: String? { if let currentUser = CurrentUserInfo.currentUser as? Self, currentUser.objectId != nil && self.objectId != nil && @@ -27,7 +27,7 @@ public extension UserType { } } -public extension UserType { +public extension ParseUser { static var current: Self? { return CurrentUserInfo.currentUser as? Self } @@ -51,7 +51,7 @@ public extension UserType { } } -private extension UserType { +private extension ParseUser { private static func loginCommand(username: String, password: String) -> API.Command { let params = [ diff --git a/Sources/ParseSwift/Objects/Queryable.swift b/Sources/ParseSwift/Objects/Queryable.swift index 5a37ad0f3..0099fac30 100644 --- a/Sources/ParseSwift/Objects/Queryable.swift +++ b/Sources/ParseSwift/Objects/Queryable.swift @@ -6,7 +6,7 @@ // Copyright © 2020 Parse. All rights reserved. // -public protocol Querying { +public protocol Queryable { associatedtype ResultType func find(options: API.Options) throws -> [ResultType] @@ -14,7 +14,7 @@ public protocol Querying { func count(options: API.Options) throws -> Int } -extension Querying { +extension Queryable { func find() throws -> [ResultType] { return try find(options: []) } diff --git a/Sources/ParseSwift/Objects/Saveable.swift b/Sources/ParseSwift/Objects/Saveable.swift index 3e46f9d87..c888e9a06 100644 --- a/Sources/ParseSwift/Objects/Saveable.swift +++ b/Sources/ParseSwift/Objects/Saveable.swift @@ -6,14 +6,14 @@ // Copyright © 2020 Parse. All rights reserved. // -public protocol Saving: Codable { +public protocol Saveable: Codable { associatedtype SavingType func save(options: API.Options) throws -> SavingType func save() throws -> SavingType } -extension Saving { +extension Saveable { public func save() throws -> SavingType { return try save(options: []) } diff --git a/Sources/ParseSwift/Parse Types/File.swift b/Sources/ParseSwift/Parse Types/File.swift index 4d933021a..47e25e945 100644 --- a/Sources/ParseSwift/Parse Types/File.swift +++ b/Sources/ParseSwift/Parse Types/File.swift @@ -1,6 +1,6 @@ import Foundation -public struct File: Saving, Fetching { +public struct File: Saveable, Fetchable { private let __type: String = "File" // swiftlint:disable:this identifier_name public var data: Data? diff --git a/Sources/ParseSwift/Parse Types/Pointer.swift b/Sources/ParseSwift/Parse Types/Pointer.swift index f74f93d55..b78bcd79e 100644 --- a/Sources/ParseSwift/Parse Types/Pointer.swift +++ b/Sources/ParseSwift/Parse Types/Pointer.swift @@ -1,13 +1,13 @@ import Foundation -private func getObjectId(target: T) -> String { +private func getObjectId(target: T) -> String { guard let objectId = target.objectId else { fatalError("Cannot set a pointer to an unsaved object") } return objectId } -public struct Pointer: Fetching, Codable { +public struct Pointer: Fetchable, Codable { public typealias FetchingType = T private let __type: String = "Pointer" // swiftlint:disable:this identifier_name diff --git a/Sources/ParseSwift/Parse Types/Query.swift b/Sources/ParseSwift/Parse Types/Query.swift index 793961691..a106ed70d 100644 --- a/Sources/ParseSwift/Parse Types/Query.swift +++ b/Sources/ParseSwift/Parse Types/Query.swift @@ -8,7 +8,7 @@ import Foundation -public struct FindResult: Decodable where T: ObjectType { +public struct FindResult: Decodable where T: ParseObject { let results: [T] let count: Int? } @@ -65,7 +65,7 @@ public func == (key: String, value: T) -> QueryConstraint where T: Encodable return QueryConstraint(key: key, value: value, comparator: .equals) } -private struct InQuery: Encodable where T: ObjectType { +private struct InQuery: Encodable where T: ParseObject { let query: Query var className: String { return T.className @@ -108,7 +108,7 @@ internal struct QueryWhere: Encodable { } } -public struct Query: Encodable where T: ObjectType { +public struct Query: Encodable where T: ParseObject { // interpolate as GET private let method: String = "GET" private var limit: Int = 100 @@ -181,7 +181,7 @@ public struct Query: Encodable where T: ObjectType { } } -extension Query: Querying { +extension Query: Queryable { public typealias ResultType = T From 3e6092d7c5adafa28ad2bd43b385dd811c4f1e41 Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Sun, 19 Jul 2020 19:13:16 -0400 Subject: [PATCH 03/30] organize ParseObject and ParseUser --- Sources/ParseSwift/Asynchronous.swift | 4 + Sources/ParseSwift/Objects/ParseObject.swift | 106 +++++++++++-------- Sources/ParseSwift/Objects/ParseUser.swift | 86 ++++++++------- 3 files changed, 111 insertions(+), 85 deletions(-) diff --git a/Sources/ParseSwift/Asynchronous.swift b/Sources/ParseSwift/Asynchronous.swift index 9698c69b3..da8d155a6 100644 --- a/Sources/ParseSwift/Asynchronous.swift +++ b/Sources/ParseSwift/Asynchronous.swift @@ -22,18 +22,21 @@ private func runAsync(options: API.Options, } } +// MARK: Saveable extension Saveable { public func save(options: API.Options = [], callback: @escaping (Self.SavingType?, Error?) -> Void) { runAsync(options: options, function: self.save, callback: callback) } } +// MARK: Fetchable extension Fetchable { public func fetch(options: API.Options = [], callback: @escaping (Self.FetchingType?, Error?) -> Void) { runAsync(options: options, function: self.fetch, callback: callback) } } +// MARK: Queryable extension Queryable { public func find(options: API.Options = [], callback: @escaping ([ResultType]?, Error?) -> Void) { runAsync(options: options, function: self.find, callback: callback) @@ -46,6 +49,7 @@ extension Queryable { } } +// MARK: Batch Support public extension ParseObject { static func saveAll(options: API.Options = [], _ objects: Self..., diff --git a/Sources/ParseSwift/Objects/ParseObject.swift b/Sources/ParseSwift/Objects/ParseObject.swift index 84fbfe03f..e8d00b425 100644 --- a/Sources/ParseSwift/Objects/ParseObject.swift +++ b/Sources/ParseSwift/Objects/ParseObject.swift @@ -8,6 +8,7 @@ import Foundation +// MARK: ParseObject public protocol ParseObject: Fetchable, Saveable, CustomDebugStringConvertible, Equatable { static var className: String { get } @@ -17,6 +18,7 @@ public protocol ParseObject: Fetchable, Saveable, CustomDebugStringConvertible, var ACL: ACL? { get set } } +// MARK: Default Implementations extension ParseObject { public static var className: String { let classType = "\(type(of: self))" @@ -28,6 +30,38 @@ extension ParseObject { } } +// MARK: Batch Support +public extension ParseObject { + static func saveAll(_ objects: Self...) throws -> [(Self, ParseError?)] { + return try objects.saveAll() + } +} + +extension Sequence where Element: ParseObject { + public func saveAll(options: API.Options = []) throws -> [(Self.Element, ParseError?)] { + let commands = map { $0.saveCommand() } + return try API.Command + .batch(commands: commands) + .execute(options: options) + } +} + +// MARK: Convenience +extension ParseObject { + var endpoint: API.Endpoint { + if let objectId = objectId { + return .object(className: className, objectId: objectId) + } + + return .objects(className: className) + } + + var isSaved: Bool { + return objectId != nil + } +} + +// MARK: CustomDebugStringConvertible extension ParseObject { public var debugDescription: String { guard let descriptionData = try? getJSONEncoder().encode(self), @@ -39,30 +73,35 @@ extension ParseObject { } } -public extension ParseObject { - func toPointer() -> Pointer { - return Pointer(self) - } +// MARK: Equatable +public func == (lhs: T?, rhs: T?) -> Bool where T: ParseObject { + guard let lhs = lhs, let rhs = rhs else { return false } + return lhs == rhs } -public extension ParseObject { - func save(options: API.Options) throws -> Self { - return try saveCommand().execute(options: options) - } +public func == (lhs: T, rhs: T) -> Bool where T: ParseObject { + return lhs.className == rhs.className && rhs.objectId == lhs.objectId +} - func fetch(options: API.Options) throws -> Self { +// MARK: Fetchable +extension ParseObject { + public func fetch(options: API.Options) throws -> Self { return try fetchCommand().execute(options: options) } - internal func saveCommand() -> API.Command { - return API.Command.saveCommand(self) - } - internal func fetchCommand() throws -> API.Command { return try API.Command.fetchCommand(self) } } +// MARK: Mutations +public extension ParseObject { + var mutationContainer: ParseMutationContainer { + return ParseMutationContainer(target: self) + } +} + +// MARK: Queryable public extension ParseObject { static func find() throws -> [Self] { return try query().find() @@ -77,46 +116,19 @@ public extension ParseObject { } } +// MARK: Saveable extension ParseObject { - var endpoint: API.Endpoint { - if let objectId = objectId { - return .object(className: className, objectId: objectId) - } - - return .objects(className: className) + public func save(options: API.Options) throws -> Self { + return try saveCommand().execute(options: options) } - var isSaved: Bool { - return objectId != nil - } -} - -public extension ParseObject { - var mutationContainer: ParseMutationContainer { - return ParseMutationContainer(target: self) + internal func saveCommand() -> API.Command { + return API.Command.saveCommand(self) } } -public func == (lhs: T?, rhs: T?) -> Bool where T: ParseObject { - guard let lhs = lhs, let rhs = rhs else { return false } - return lhs == rhs -} - -public func == (lhs: T, rhs: T) -> Bool where T: ParseObject { - return lhs.className == rhs.className && rhs.objectId == lhs.objectId -} - public extension ParseObject { - static func saveAll(_ objects: Self...) throws -> [(Self, ParseError?)] { - return try objects.saveAll() - } -} - -extension Sequence where Element: ParseObject { - public func saveAll(options: API.Options = []) throws -> [(Self.Element, ParseError?)] { - let commands = map { $0.saveCommand() } - return try API.Command - .batch(commands: commands) - .execute(options: options) + func toPointer() -> Pointer { + return Pointer(self) } } diff --git a/Sources/ParseSwift/Objects/ParseUser.swift b/Sources/ParseSwift/Objects/ParseUser.swift index 72cb6da2b..43ce69acf 100644 --- a/Sources/ParseSwift/Objects/ParseUser.swift +++ b/Sources/ParseSwift/Objects/ParseUser.swift @@ -1,17 +1,28 @@ import Foundation +// MARK: CurrentUserInfo internal struct CurrentUserInfo { static var currentUser: Any? static var currentSessionToken: String? } +// MARK: ParseUser public protocol ParseUser: ParseObject { var username: String? { get set } var email: String? { get set } var password: String? { get set } } +// MARK: Convenience public extension ParseUser { + static var className: String { + return "_User" + } + + static var current: Self? { + return CurrentUserInfo.currentUser as? Self + } + var sessionToken: String? { if let currentUser = CurrentUserInfo.currentUser as? Self, currentUser.objectId != nil && self.objectId != nil && @@ -21,37 +32,15 @@ public extension ParseUser { return nil } - - static var className: String { - return "_User" - } } -public extension ParseUser { - static var current: Self? { - return CurrentUserInfo.currentUser as? Self - } - - static func login(username: String, +// MARK: Logging In +extension ParseUser { + public static func login(username: String, password: String) throws -> Self { return try loginCommand(username: username, password: password).execute(options: []) } - - static func signup(username: String, - password: String) throws -> Self { - return try signupCommand(username: username, password: password).execute(options: []) - } - - static func logout() throws { - _ = try logoutCommand().execute(options: []) - } - - func signup() throws -> Self { - return try signupCommand().execute(options: []) - } -} - -private extension ParseUser { + private static func loginCommand(username: String, password: String) -> API.Command { let params = [ @@ -69,6 +58,32 @@ private extension ParseUser { return user } } +} + +// MARK: Logging Out +extension ParseUser { + public static func logout() throws { + _ = try logoutCommand().execute(options: []) + } + + private static func logoutCommand() -> API.Command { + return API.Command(method: .POST, path: .logout) { (_) -> Void in + CurrentUserInfo.currentUser = nil + CurrentUserInfo.currentSessionToken = nil + } + } +} + +// MARK: Signing Up +extension ParseUser { + public static func signup(username: String, + password: String) throws -> Self { + return try signupCommand(username: username, password: password).execute(options: []) + } + + public func signup() throws -> Self { + return try signupCommand().execute(options: []) + } private static func signupCommand(username: String, password: String) -> API.Command { @@ -100,23 +115,18 @@ private extension ParseUser { return user } } - - private static func logoutCommand() -> API.Command { - return API.Command(method: .POST, path: .logout) { (_) -> Void in - CurrentUserInfo.currentUser = nil - CurrentUserInfo.currentSessionToken = nil - } - } -} - -public struct SignupBody: Codable { - let username: String - let password: String } +// MARK: LoginSignupResponse private struct LoginSignupResponse: Codable { let createdAt: Date let objectId: String let sessionToken: String var updatedAt: Date? } + +// MARK: SignupBody +public struct SignupBody: Codable { + let username: String + let password: String +} From ef37863a517c12b9566498c8024b961436717428 Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Sun, 19 Jul 2020 20:08:15 -0400 Subject: [PATCH 04/30] organize Coding --- Sources/ParseSwift/API/API+Commands.swift | 12 +-- Sources/ParseSwift/Coding/Extensions.swift | 37 +++++++ Sources/ParseSwift/Coding/Miscellaneous.swift | 100 ------------------ Sources/ParseSwift/Coding/ParseCoding.swift | 87 +++++++++++++++ Sources/ParseSwift/Objects/ParseObject.swift | 2 +- Sources/ParseSwift/Objects/ParseUser.swift | 10 +- Sources/ParseSwift/Parse Types/Pointer.swift | 2 +- Sources/ParseSwift/Parse Types/Query.swift | 6 +- 8 files changed, 140 insertions(+), 116 deletions(-) create mode 100644 Sources/ParseSwift/Coding/Extensions.swift delete mode 100644 Sources/ParseSwift/Coding/Miscellaneous.swift create mode 100644 Sources/ParseSwift/Coding/ParseCoding.swift diff --git a/Sources/ParseSwift/API/API+Commands.swift b/Sources/ParseSwift/API/API+Commands.swift index c17c4f82e..c19c9a465 100644 --- a/Sources/ParseSwift/API/API+Commands.swift +++ b/Sources/ParseSwift/API/API+Commands.swift @@ -18,7 +18,7 @@ internal extension API { let params: [String: String?]? internal var data: Data? { - return try? getJSONEncoder().encode(body) + return try? ParseCoding.jsonEncoder().encode(body) } init(method: API.Method, @@ -51,7 +51,7 @@ internal extension API { do { return try mapper(responseData) } catch _ { - throw try getDecoder().decode(ParseError.self, from: responseData) + throw try ParseCoding.jsonDecoder().decode(ParseError.self, from: responseData) } } @@ -73,7 +73,7 @@ internal extension API.Command { // MARK: Saving - private private static func createCommand(_ object: T) -> API.Command where T: ParseObject { let mapper = { (data) -> T in - try getDecoder().decode(SaveResponse.self, from: data).apply(object) + try ParseCoding.jsonDecoder().decode(SaveResponse.self, from: data).apply(object) } return API.Command(method: .POST, path: object.endpoint, @@ -83,7 +83,7 @@ internal extension API.Command { private static func updateCommand(_ object: T) -> API.Command where T: ParseObject { let mapper = { (data: Data) -> T in - try getDecoder().decode(UpdateResponse.self, from: data).apply(object) + try ParseCoding.jsonDecoder().decode(UpdateResponse.self, from: data).apply(object) } return API.Command(method: .PUT, path: object.endpoint, @@ -98,7 +98,7 @@ internal extension API.Command { } return API.Command(method: .GET, path: object.endpoint) { (data) -> T in - try getDecoder().decode(T.self, from: data) + try ParseCoding.jsonDecoder().decode(T.self, from: data) } } } @@ -124,7 +124,7 @@ extension API.Command where T: ParseObject { } let mapper = { (data: Data) -> [(T, ParseError?)] in let decodingType = [BatchResponseItem].self - let responses = try getDecoder().decode(decodingType, from: data) + let responses = try ParseCoding.jsonDecoder().decode(decodingType, from: data) return bodies.enumerated().map({ (object) -> (T, ParseError?) in let response = responses[object.0] if let success = response.success { diff --git a/Sources/ParseSwift/Coding/Extensions.swift b/Sources/ParseSwift/Coding/Extensions.swift new file mode 100644 index 000000000..0e2d6341e --- /dev/null +++ b/Sources/ParseSwift/Coding/Extensions.swift @@ -0,0 +1,37 @@ +// +// File.swift +// +// +// Created by Pranjal Satija on 7/19/20. +// + +import Foundation + +// MARK: Date +internal extension Date { + func parseFormatted() -> String { + return ParseCoding.dateFormatter.string(from: self) + } + + var parseRepresentation: [String: String] { + return ["__type": "Date", "iso": parseFormatted()] + } +} + +// MARK: JSONEncoder +extension JSONEncoder { + func encodeAsString(_ value: T) throws -> String where T: Encodable { + guard let string = String(data: try encode(value), encoding: .utf8) else { + throw ParseError(code: .unknownError, message: "Unable to encode object...") + } + + return string + } +} + +// MARK: ParseObject +internal extension ParseObject { + func getEncoder() -> ParseEncoder { + return ParseCoding.parseEncoder() + } +} diff --git a/Sources/ParseSwift/Coding/Miscellaneous.swift b/Sources/ParseSwift/Coding/Miscellaneous.swift deleted file mode 100644 index 632d45c44..000000000 --- a/Sources/ParseSwift/Coding/Miscellaneous.swift +++ /dev/null @@ -1,100 +0,0 @@ -// -// ParseObjectType.swift -// ParseSwift -// -// Created by Florent Vilmart on 17-07-24. -// Copyright © 2017 Parse. All rights reserved. -// - -import Foundation - -internal extension ParseObject { - func getEncoder() -> ParseEncoder { - return getParseEncoder() - } -} - -enum DateEncodingKeys: String, CodingKey { - case iso - case type = "__type" -} - -let dateFormatter: DateFormatter = { - var dateFormatter = DateFormatter() - dateFormatter.locale = Locale(identifier: "") - dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" - return dateFormatter -}() - -let parseDateEncodingStrategy: ParseEncoder.DateEncodingStrategy = .custom({ (date, enc) in - var container = enc.container(keyedBy: DateEncodingKeys.self) - try container.encode("Date", forKey: .type) - let dateString = dateFormatter.string(from: date) - try container.encode(dateString, forKey: .iso) -}) - -let dateEncodingStrategy: JSONEncoder.DateEncodingStrategy = .custom({ (date, enc) in - var container = enc.container(keyedBy: DateEncodingKeys.self) - try container.encode("Date", forKey: .type) - let dateString = dateFormatter.string(from: date) - try container.encode(dateString, forKey: .iso) -}) - -internal extension Date { - func parseFormatted() -> String { - return dateFormatter.string(from: self) - } - var parseRepresentation: [String: String] { - return ["__type": "Date", "iso": parseFormatted()] - } -} - -let dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .custom({ (dec) -> Date in - do { - let container = try dec.singleValueContainer() - let decodedString = try container.decode(String.self) - return dateFormatter.date(from: decodedString)! - } catch let error { - let container = try dec.container(keyedBy: DateEncodingKeys.self) - if let decoded = try container.decodeIfPresent(String.self, forKey: .iso) { - return dateFormatter.date(from: decoded)! - } - } - throw ParseError(code: .unknownError, message: "unable to decode") -}) - -func getJSONEncoder() -> JSONEncoder { - let encoder = JSONEncoder() - encoder.dateEncodingStrategy = dateEncodingStrategy - return encoder -} - -private let forbiddenKeys = ["createdAt", "updatedAt", "objectId", "className"] - -func getParseEncoder() -> ParseEncoder { - let encoder = ParseEncoder() - encoder.dateEncodingStrategy = parseDateEncodingStrategy - encoder.shouldEncodeKey = { (key, path) -> Bool in - if path.count == 0 // top level - && forbiddenKeys.firstIndex(of: key) != nil { - return false - } - return true - } - return encoder -} - -extension JSONEncoder { - func encodeAsString(_ value: T) throws -> String where T: Encodable { - guard let string = String(data: try encode(value), encoding: .utf8) else { - throw ParseError(code: .unknownError, message: "Unable to encode object...") - } - return string - } -} - -func getDecoder() -> JSONDecoder { - let encoder = JSONDecoder() - encoder.dateDecodingStrategy = dateDecodingStrategy - return encoder -} diff --git a/Sources/ParseSwift/Coding/ParseCoding.swift b/Sources/ParseSwift/Coding/ParseCoding.swift new file mode 100644 index 000000000..397a29028 --- /dev/null +++ b/Sources/ParseSwift/Coding/ParseCoding.swift @@ -0,0 +1,87 @@ +// +// ParseObjectType.swift +// ParseSwift +// +// Created by Florent Vilmart on 17-07-24. +// Copyright © 2017 Parse. All rights reserved. +// + +import Foundation + +// MARK: ParseCoding +internal enum ParseCoding {} + +// MARK: Coders +extension ParseCoding { + private static let forbiddenKeys = Set(["createdAt", "updatedAt", "objectId", "className"]) + + static func jsonEncoder() -> JSONEncoder { + let encoder = JSONEncoder() + encoder.dateEncodingStrategy = jsonDateEncodingStrategy + return encoder + } + + static func jsonDecoder() -> JSONDecoder { + let encoder = JSONDecoder() + encoder.dateDecodingStrategy = jsonDateDecodingStrategy + return encoder + } + + static func parseEncoder() -> ParseEncoder { + let encoder = ParseEncoder() + encoder.dateEncodingStrategy = parseDateEncodingStrategy + encoder.shouldEncodeKey = { (key, path) -> Bool in + if path.count == 0 // top level + && Self.forbiddenKeys.contains(key) { + return false + } + return true + } + + return encoder + } +} + +// MARK: Dates +extension ParseCoding { + enum DateEncodingKeys: String, CodingKey { + case iso + case type = "__type" + } + + static let dateFormatter: DateFormatter = { + var dateFormatter = DateFormatter() + dateFormatter.locale = Locale(identifier: "") + dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" + return dateFormatter + }() + + static let jsonDateEncodingStrategy: JSONEncoder.DateEncodingStrategy = .custom({ (date, enc) in + var container = enc.container(keyedBy: DateEncodingKeys.self) + try container.encode("Date", forKey: .type) + let dateString = dateFormatter.string(from: date) + try container.encode(dateString, forKey: .iso) + }) + + static let parseDateEncodingStrategy: ParseEncoder.DateEncodingStrategy = .custom({ (date, enc) in + var container = enc.container(keyedBy: DateEncodingKeys.self) + try container.encode("Date", forKey: .type) + let dateString = dateFormatter.string(from: date) + try container.encode(dateString, forKey: .iso) + }) + + static let jsonDateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .custom({ (dec) -> Date in + do { + let container = try dec.singleValueContainer() + let decodedString = try container.decode(String.self) + return dateFormatter.date(from: decodedString)! + } catch let error { + let container = try dec.container(keyedBy: DateEncodingKeys.self) + if let decoded = try container.decodeIfPresent(String.self, forKey: .iso) { + return dateFormatter.date(from: decoded)! + } + } + + throw ParseError(code: .unknownError, message: "unable to decode") + }) +} diff --git a/Sources/ParseSwift/Objects/ParseObject.swift b/Sources/ParseSwift/Objects/ParseObject.swift index e8d00b425..ff5cd5b2c 100644 --- a/Sources/ParseSwift/Objects/ParseObject.swift +++ b/Sources/ParseSwift/Objects/ParseObject.swift @@ -64,7 +64,7 @@ extension ParseObject { // MARK: CustomDebugStringConvertible extension ParseObject { public var debugDescription: String { - guard let descriptionData = try? getJSONEncoder().encode(self), + guard let descriptionData = try? ParseCoding.jsonEncoder().encode(self), let descriptionString = String(data: descriptionData, encoding: .utf8) else { return "\(className) ()" } diff --git a/Sources/ParseSwift/Objects/ParseUser.swift b/Sources/ParseSwift/Objects/ParseUser.swift index 43ce69acf..514155dfc 100644 --- a/Sources/ParseSwift/Objects/ParseUser.swift +++ b/Sources/ParseSwift/Objects/ParseUser.swift @@ -51,8 +51,8 @@ extension ParseUser { return API.Command(method: .GET, path: .login, params: params) { (data) -> Self in - let user = try getDecoder().decode(Self.self, from: data) - let response = try getDecoder().decode(LoginSignupResponse.self, from: data) + let user = try ParseCoding.jsonDecoder().decode(Self.self, from: data) + let response = try ParseCoding.jsonDecoder().decode(LoginSignupResponse.self, from: data) CurrentUserInfo.currentUser = user CurrentUserInfo.currentSessionToken = response.sessionToken return user @@ -90,8 +90,8 @@ extension ParseUser { let body = SignupBody(username: username, password: password) return API.Command(method: .POST, path: .signup, body: body) { (data) -> Self in - let response = try getDecoder().decode(LoginSignupResponse.self, from: data) - var user = try getDecoder().decode(Self.self, from: data) + let response = try ParseCoding.jsonDecoder().decode(LoginSignupResponse.self, from: data) + var user = try ParseCoding.jsonDecoder().decode(Self.self, from: data) user.username = username user.password = password user.updatedAt = response.updatedAt ?? response.createdAt @@ -106,7 +106,7 @@ extension ParseUser { private func signupCommand() -> API.Command { var user = self return API.Command(method: .POST, path: .signup, body: user) { (data) -> Self in - let response = try getDecoder().decode(LoginSignupResponse.self, from: data) + let response = try ParseCoding.jsonDecoder().decode(LoginSignupResponse.self, from: data) user.updatedAt = response.updatedAt ?? response.createdAt user.createdAt = response.createdAt // Set the current user diff --git a/Sources/ParseSwift/Parse Types/Pointer.swift b/Sources/ParseSwift/Parse Types/Pointer.swift index b78bcd79e..114d55d1a 100644 --- a/Sources/ParseSwift/Parse Types/Pointer.swift +++ b/Sources/ParseSwift/Parse Types/Pointer.swift @@ -34,7 +34,7 @@ extension Pointer { let path = API.Endpoint.object(className: className, objectId: objectId) return try API.Command(method: .GET, path: path) { (data) -> T in - try getDecoder().decode(T.self, from: data) + try ParseCoding.jsonDecoder().decode(T.self, from: data) }.execute(options: options) } } diff --git a/Sources/ParseSwift/Parse Types/Query.swift b/Sources/ParseSwift/Parse Types/Query.swift index a106ed70d..e9df4d815 100644 --- a/Sources/ParseSwift/Parse Types/Query.swift +++ b/Sources/ParseSwift/Parse Types/Query.swift @@ -201,7 +201,7 @@ extension Query: Queryable { private extension Query { private func findCommand() -> API.Command, [ResultType]> { return API.Command(method: .POST, path: endpoint, body: self) { - try getDecoder().decode(FindResult.self, from: $0).results + try ParseCoding.jsonDecoder().decode(FindResult.self, from: $0).results } } @@ -209,7 +209,7 @@ private extension Query { var query = self query.limit = 1 return API.Command(method: .POST, path: endpoint, body: query) { - try getDecoder().decode(FindResult.self, from: $0).results.first + try ParseCoding.jsonDecoder().decode(FindResult.self, from: $0).results.first } } @@ -218,7 +218,7 @@ private extension Query { query.limit = 1 query.isCount = true return API.Command(method: .POST, path: endpoint, body: query) { - try getDecoder().decode(FindResult.self, from: $0).count ?? 0 + try ParseCoding.jsonDecoder().decode(FindResult.self, from: $0).count ?? 0 } } } From 00f4622b725b0058463c1e984c4f83ffb941bad1 Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Sun, 19 Jul 2020 20:08:32 -0400 Subject: [PATCH 05/30] add IDEWorkspaceChecks https://stackoverflow.com/questions/49564513/new-file-created-in-xcode-9-3-wsname-xcworkspace-xcshareddata-ideworkspaceche --- Parse.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 Parse.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Parse.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Parse.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/Parse.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 3547627753e40429d43385b211ae6454109aecd8 Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Sun, 19 Jul 2020 21:44:20 -0400 Subject: [PATCH 06/30] add PrimitiveObjectStore and friends --- ParseSwift.xcodeproj/project.pbxproj | 38 ++++++++-- Sources/ParseSwift/API/API.swift | 2 +- Sources/ParseSwift/Coding/Extensions.swift | 4 +- Sources/ParseSwift/Coding/ParseCoding.swift | 12 +-- .../ParseMutationContainer.swift | 2 +- Sources/ParseSwift/Objects/ParseUser.swift | 73 +++++++++++-------- .../Parse Types/BaseParseUser.swift | 20 +++++ Sources/ParseSwift/Storage/ParseStorage.swift | 43 +++++++++++ .../Storage/PrimitiveObjectStore.swift | 53 ++++++++++++++ 9 files changed, 199 insertions(+), 48 deletions(-) create mode 100644 Sources/ParseSwift/Parse Types/BaseParseUser.swift create mode 100644 Sources/ParseSwift/Storage/ParseStorage.swift create mode 100644 Sources/ParseSwift/Storage/PrimitiveObjectStore.swift diff --git a/ParseSwift.xcodeproj/project.pbxproj b/ParseSwift.xcodeproj/project.pbxproj index cd578686b..4d5a2a2ad 100644 --- a/ParseSwift.xcodeproj/project.pbxproj +++ b/ParseSwift.xcodeproj/project.pbxproj @@ -18,7 +18,6 @@ 4A82B7F41F254CCE0063D731 /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7F01F254B820063D731 /* File.swift */; }; 4A82B7F51F254CCE0063D731 /* GeoPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7ED1F254B820063D731 /* GeoPoint.swift */; }; 4A82B7F61F254CCE0063D731 /* Parse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EE1F254B820063D731 /* Parse.swift */; }; - 4A82B7F71F254CCE0063D731 /* Miscellaneous.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EC1F254B820063D731 /* Miscellaneous.swift */; }; 4A82B7F81F254CCE0063D731 /* Pointer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7F11F254B820063D731 /* Pointer.swift */; }; 4A82B7FF1F256A8F0063D731 /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7FE1F256A8F0063D731 /* Query.swift */; }; 4A99A4691F2650CA00D72A59 /* ParseMutationContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A99A4681F2650CA00D72A59 /* ParseMutationContainer.swift */; }; @@ -52,7 +51,6 @@ 4AF85BDD1F783B9800665264 /* API+Commands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AF85BDC1F783B9800665264 /* API+Commands.swift */; }; 4AF85BDE1F783BB400665264 /* API+Commands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AF85BDC1F783B9800665264 /* API+Commands.swift */; }; 4AFDA72A1F26DAE1002AE4FC /* Parse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EE1F254B820063D731 /* Parse.swift */; }; - 4AFDA72B1F26DAE1002AE4FC /* Miscellaneous.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EC1F254B820063D731 /* Miscellaneous.swift */; }; 4AFDA72C1F26DAE1002AE4FC /* ParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA54E1F265A0D00628B17 /* ParseUser.swift */; }; 4AFDA72D1F26DAE1002AE4FC /* ParseMutationContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A99A4681F2650CA00D72A59 /* ParseMutationContainer.swift */; }; 4AFDA72E1F26DAE1002AE4FC /* AddOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA5481F26519B00628B17 /* AddOperation.swift */; }; @@ -83,6 +81,16 @@ F92B578B24C3F09600A43E8D /* Queryable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F92B578924C3F09600A43E8D /* Queryable.swift */; }; F92B578D24C3F0F300A43E8D /* NoBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = F92B578C24C3F0F300A43E8D /* NoBody.swift */; }; F92B578E24C3F0F300A43E8D /* NoBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = F92B578C24C3F0F300A43E8D /* NoBody.swift */; }; + F980C99424C52DD900262E4F /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F980C99224C52DD800262E4F /* Extensions.swift */; }; + F980C99524C52DD900262E4F /* ParseCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = F980C99324C52DD900262E4F /* ParseCoding.swift */; }; + F980C99624C52DE100262E4F /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F980C99224C52DD800262E4F /* Extensions.swift */; }; + F980C99724C52DE100262E4F /* ParseCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = F980C99324C52DD900262E4F /* ParseCoding.swift */; }; + F980C99924C52E0200262E4F /* BaseParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F980C99824C52E0200262E4F /* BaseParseUser.swift */; }; + F980C99C24C52E1900262E4F /* ParseStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F980C99A24C52E1900262E4F /* ParseStorage.swift */; }; + F980C99D24C52E1900262E4F /* PrimitiveObjectStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F980C99B24C52E1900262E4F /* PrimitiveObjectStore.swift */; }; + F980C99E24C52E1D00262E4F /* PrimitiveObjectStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F980C99B24C52E1900262E4F /* PrimitiveObjectStore.swift */; }; + F980C99F24C52E1D00262E4F /* ParseStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F980C99A24C52E1900262E4F /* ParseStorage.swift */; }; + F980C9A024C5395400262E4F /* BaseParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F980C99824C52E0200262E4F /* BaseParseUser.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -107,7 +115,6 @@ 4A2D8C801F48B3A900EE1FCC /* ParseEncoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseEncoder.swift; sourceTree = ""; }; 4A2F14901F4A41B900A7A7EF /* Asynchronous.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Asynchronous.swift; sourceTree = ""; }; 4A2F14951F4A5F2900A7A7EF /* Responses.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Responses.swift; sourceTree = ""; }; - 4A82B7EC1F254B820063D731 /* Miscellaneous.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Miscellaneous.swift; sourceTree = ""; }; 4A82B7ED1F254B820063D731 /* GeoPoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoPoint.swift; sourceTree = ""; }; 4A82B7EE1F254B820063D731 /* Parse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Parse.swift; sourceTree = ""; }; 4A82B7F01F254B820063D731 /* File.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = File.swift; sourceTree = ""; }; @@ -155,6 +162,11 @@ F92B578624C3F02D00A43E8D /* Saveable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Saveable.swift; sourceTree = ""; }; F92B578924C3F09600A43E8D /* Queryable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Queryable.swift; sourceTree = ""; }; F92B578C24C3F0F300A43E8D /* NoBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoBody.swift; sourceTree = ""; }; + F980C99224C52DD800262E4F /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; + F980C99324C52DD900262E4F /* ParseCoding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseCoding.swift; sourceTree = ""; }; + F980C99824C52E0200262E4F /* BaseParseUser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseParseUser.swift; sourceTree = ""; }; + F980C99A24C52E1900262E4F /* ParseStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseStorage.swift; sourceTree = ""; }; + F980C99B24C52E1900262E4F /* PrimitiveObjectStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrimitiveObjectStore.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -219,6 +231,7 @@ isa = PBXGroup; children = ( 4AC3976F1F48778900DEA9D3 /* ACL.swift */, + F980C99824C52E0200262E4F /* BaseParseUser.swift */, 4AF85BD21F78011100665264 /* ParseError.swift */, 4A82B7F01F254B820063D731 /* File.swift */, 4A82B7ED1F254B820063D731 /* GeoPoint.swift */, @@ -246,8 +259,10 @@ 4AA807491F7930D0008CD551 /* Storage */ = { isa = PBXGroup; children = ( - 4AA8074A1F7930E9008CD551 /* SecureStorage.swift */, 4AA8074D1F7931B7008CD551 /* KeychainStore.swift */, + F980C99A24C52E1900262E4F /* ParseStorage.swift */, + F980C99B24C52E1900262E4F /* PrimitiveObjectStore.swift */, + 4AA8074A1F7930E9008CD551 /* SecureStorage.swift */, ); path = Storage; sourceTree = ""; @@ -353,7 +368,8 @@ 709075C424B9117400B95310 /* AnyCodable.swift */, 709075C524B9117500B95310 /* AnyDecodable.swift */, 709075C624B9117500B95310 /* AnyEncodable.swift */, - 4A82B7EC1F254B820063D731 /* Miscellaneous.swift */, + F980C99224C52DD800262E4F /* Extensions.swift */, + F980C99324C52DD900262E4F /* ParseCoding.swift */, 4A2D8C801F48B3A900EE1FCC /* ParseEncoder.swift */, ); path = Coding; @@ -597,7 +613,6 @@ 4A2F14961F4A5F2900A7A7EF /* Responses.swift in Sources */, 709075C724B9117500B95310 /* AnyCodable.swift in Sources */, 4AC397741F488FF900DEA9D3 /* API.swift in Sources */, - 4A82B7F71F254CCE0063D731 /* Miscellaneous.swift in Sources */, 4A82B7F51F254CCE0063D731 /* GeoPoint.swift in Sources */, 4AA8074B1F7930E9008CD551 /* SecureStorage.swift in Sources */, 4A82B7F61F254CCE0063D731 /* Parse.swift in Sources */, @@ -622,9 +637,14 @@ 4AEBA54D1F26523800628B17 /* DeleteOperation.swift in Sources */, 4AF85BDD1F783B9800665264 /* API+Commands.swift in Sources */, 4A82B7F81F254CCE0063D731 /* Pointer.swift in Sources */, + F980C99C24C52E1900262E4F /* ParseStorage.swift in Sources */, 709075C924B9117500B95310 /* AnyDecodable.swift in Sources */, + F980C99524C52DD900262E4F /* ParseCoding.swift in Sources */, + F980C99D24C52E1900262E4F /* PrimitiveObjectStore.swift in Sources */, + F980C99924C52E0200262E4F /* BaseParseUser.swift in Sources */, 4AEBA5491F26519B00628B17 /* AddOperation.swift in Sources */, 4A99A46C1F2650FF00D72A59 /* AddUniqueOperation.swift in Sources */, + F980C99424C52DD900262E4F /* Extensions.swift in Sources */, 4AEBA54B1F2651D900628B17 /* RemoveOperation.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -645,9 +665,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 4AFDA72B1F26DAE1002AE4FC /* Miscellaneous.swift in Sources */, + F980C99E24C52E1D00262E4F /* PrimitiveObjectStore.swift in Sources */, 709075C824B9117500B95310 /* AnyCodable.swift in Sources */, 4AFDA7301F26DAE1002AE4FC /* DeleteOperation.swift in Sources */, + F980C9A024C5395400262E4F /* BaseParseUser.swift in Sources */, 4AFDA7341F26DAE1002AE4FC /* Pointer.swift in Sources */, 4AA8074C1F7930E9008CD551 /* SecureStorage.swift in Sources */, 4A6511501F48E400005237DF /* BatchUtils.swift in Sources */, @@ -672,10 +693,13 @@ F92B578B24C3F09600A43E8D /* Queryable.swift in Sources */, 4AFDA7321F26DAE1002AE4FC /* IncrementOperation.swift in Sources */, 4AF85BDE1F783BB400665264 /* API+Commands.swift in Sources */, + F980C99F24C52E1D00262E4F /* ParseStorage.swift in Sources */, 4AFDA72D1F26DAE1002AE4FC /* ParseMutationContainer.swift in Sources */, 709075CA24B9117500B95310 /* AnyDecodable.swift in Sources */, + F980C99724C52DE100262E4F /* ParseCoding.swift in Sources */, 4AFDA72C1F26DAE1002AE4FC /* ParseUser.swift in Sources */, 4A6511511F48E406005237DF /* ACL.swift in Sources */, + F980C99624C52DE100262E4F /* Extensions.swift in Sources */, 4AFDA72F1F26DAE1002AE4FC /* RemoveOperation.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Sources/ParseSwift/API/API.swift b/Sources/ParseSwift/API/API.swift index b559d5901..39c3b696f 100644 --- a/Sources/ParseSwift/API/API.swift +++ b/Sources/ParseSwift/API/API.swift @@ -75,7 +75,7 @@ public struct API { headers["X-Parse-Client-Key"] = clientKey } - if let token = CurrentUserInfo.currentSessionToken { + if let token = BaseParseUser.currentUserContainer?.sessionToken { headers["X-Parse-Session-Token"] = token } diff --git a/Sources/ParseSwift/Coding/Extensions.swift b/Sources/ParseSwift/Coding/Extensions.swift index 0e2d6341e..c12b79755 100644 --- a/Sources/ParseSwift/Coding/Extensions.swift +++ b/Sources/ParseSwift/Coding/Extensions.swift @@ -12,7 +12,7 @@ internal extension Date { func parseFormatted() -> String { return ParseCoding.dateFormatter.string(from: self) } - + var parseRepresentation: [String: String] { return ["__type": "Date", "iso": parseFormatted()] } @@ -24,7 +24,7 @@ extension JSONEncoder { guard let string = String(data: try encode(value), encoding: .utf8) else { throw ParseError(code: .unknownError, message: "Unable to encode object...") } - + return string } } diff --git a/Sources/ParseSwift/Coding/ParseCoding.swift b/Sources/ParseSwift/Coding/ParseCoding.swift index 397a29028..5ba4972ca 100644 --- a/Sources/ParseSwift/Coding/ParseCoding.swift +++ b/Sources/ParseSwift/Coding/ParseCoding.swift @@ -14,13 +14,13 @@ internal enum ParseCoding {} // MARK: Coders extension ParseCoding { private static let forbiddenKeys = Set(["createdAt", "updatedAt", "objectId", "className"]) - + static func jsonEncoder() -> JSONEncoder { let encoder = JSONEncoder() encoder.dateEncodingStrategy = jsonDateEncodingStrategy return encoder } - + static func jsonDecoder() -> JSONDecoder { let encoder = JSONDecoder() encoder.dateDecodingStrategy = jsonDateDecodingStrategy @@ -37,7 +37,7 @@ extension ParseCoding { } return true } - + return encoder } } @@ -48,7 +48,7 @@ extension ParseCoding { case iso case type = "__type" } - + static let dateFormatter: DateFormatter = { var dateFormatter = DateFormatter() dateFormatter.locale = Locale(identifier: "") @@ -62,7 +62,7 @@ extension ParseCoding { let dateString = dateFormatter.string(from: date) try container.encode(dateString, forKey: .iso) }) - + static let parseDateEncodingStrategy: ParseEncoder.DateEncodingStrategy = .custom({ (date, enc) in var container = enc.container(keyedBy: DateEncodingKeys.self) try container.encode("Date", forKey: .type) @@ -81,7 +81,7 @@ extension ParseCoding { return dateFormatter.date(from: decoded)! } } - + throw ParseError(code: .unknownError, message: "unable to decode") }) } diff --git a/Sources/ParseSwift/MutationOperations/ParseMutationContainer.swift b/Sources/ParseSwift/MutationOperations/ParseMutationContainer.swift index 02e7bb25c..f02a58d35 100644 --- a/Sources/ParseSwift/MutationOperations/ParseMutationContainer.swift +++ b/Sources/ParseSwift/MutationOperations/ParseMutationContainer.swift @@ -10,7 +10,7 @@ import Foundation public struct ParseMutationContainer: Encodable where T: ParseObject { typealias ObjectType = T - + var target: T private var operations = [String: Encodable]() diff --git a/Sources/ParseSwift/Objects/ParseUser.swift b/Sources/ParseSwift/Objects/ParseUser.swift index 514155dfc..692f4e584 100644 --- a/Sources/ParseSwift/Objects/ParseUser.swift +++ b/Sources/ParseSwift/Objects/ParseUser.swift @@ -1,9 +1,9 @@ import Foundation -// MARK: CurrentUserInfo -internal struct CurrentUserInfo { - static var currentUser: Any? - static var currentSessionToken: String? +// MARK: CurrentUserContainer +struct CurrentUserContainer: Codable { + var currentUser: T? + var sessionToken: String? } // MARK: ParseUser @@ -13,34 +13,37 @@ public protocol ParseUser: ParseObject { var password: String? { get set } } -// MARK: Convenience +// MARK: Default Implementations public extension ParseUser { static var className: String { return "_User" } - - static var current: Self? { - return CurrentUserInfo.currentUser as? Self +} + +// MARK: Current User Support +extension ParseUser { + static var currentUserContainer: CurrentUserContainer? { + get { try? ParseStorage.shared.get(valueFor: ParseStorage.Keys.currentUser) } + set { try? ParseStorage.shared.set(newValue, for: ParseStorage.Keys.currentUser) } } - - var sessionToken: String? { - if let currentUser = CurrentUserInfo.currentUser as? Self, - currentUser.objectId != nil && self.objectId != nil && - currentUser.objectId == self.objectId { - return CurrentUserInfo.currentSessionToken - } - return nil + public static var current: Self? { + get { Self.currentUserContainer?.currentUser } + set { Self.currentUserContainer?.currentUser = newValue } + } + + public var sessionToken: String? { + Self.currentUserContainer?.sessionToken } } // MARK: Logging In extension ParseUser { public static func login(username: String, - password: String) throws -> Self { + password: String) throws -> Self { return try loginCommand(username: username, password: password).execute(options: []) } - + private static func loginCommand(username: String, password: String) -> API.Command { let params = [ @@ -53,8 +56,12 @@ extension ParseUser { params: params) { (data) -> Self in let user = try ParseCoding.jsonDecoder().decode(Self.self, from: data) let response = try ParseCoding.jsonDecoder().decode(LoginSignupResponse.self, from: data) - CurrentUserInfo.currentUser = user - CurrentUserInfo.currentSessionToken = response.sessionToken + + Self.currentUserContainer = .init( + currentUser: user, + sessionToken: response.sessionToken + ) + return user } } @@ -65,11 +72,10 @@ extension ParseUser { public static func logout() throws { _ = try logoutCommand().execute(options: []) } - + private static func logoutCommand() -> API.Command { return API.Command(method: .POST, path: .logout) { (_) -> Void in - CurrentUserInfo.currentUser = nil - CurrentUserInfo.currentSessionToken = nil + currentUserContainer = nil } } } @@ -77,10 +83,10 @@ extension ParseUser { // MARK: Signing Up extension ParseUser { public static func signup(username: String, - password: String) throws -> Self { + password: String) throws -> Self { return try signupCommand(username: username, password: password).execute(options: []) } - + public func signup() throws -> Self { return try signupCommand().execute(options: []) } @@ -96,9 +102,11 @@ extension ParseUser { user.password = password user.updatedAt = response.updatedAt ?? response.createdAt - // Set the current user - CurrentUserInfo.currentUser = user - CurrentUserInfo.currentSessionToken = response.sessionToken + currentUserContainer = .init( + currentUser: user, + sessionToken: response.sessionToken + ) + return user } } @@ -109,9 +117,12 @@ extension ParseUser { let response = try ParseCoding.jsonDecoder().decode(LoginSignupResponse.self, from: data) user.updatedAt = response.updatedAt ?? response.createdAt user.createdAt = response.createdAt - // Set the current user - CurrentUserInfo.currentUser = user - CurrentUserInfo.currentSessionToken = response.sessionToken + + Self.currentUserContainer = .init( + currentUser: user, + sessionToken: response.sessionToken + ) + return user } } diff --git a/Sources/ParseSwift/Parse Types/BaseParseUser.swift b/Sources/ParseSwift/Parse Types/BaseParseUser.swift new file mode 100644 index 000000000..6da18af38 --- /dev/null +++ b/Sources/ParseSwift/Parse Types/BaseParseUser.swift @@ -0,0 +1,20 @@ +// +// File 2.swift +// +// +// Created by Pranjal Satija on 7/19/20. +// + +import Foundation + +/// Used internally to form a concrete type representing `ParseUser`. +/// `ParseUser` itself has associatedtype requirements, so it's often awkard to use it directly. +struct BaseParseUser: ParseUser { + var username: String? + var email: String? + var password: String? + var objectId: String? + var createdAt: Date? + var updatedAt: Date? + var ACL: ACL? +} diff --git a/Sources/ParseSwift/Storage/ParseStorage.swift b/Sources/ParseSwift/Storage/ParseStorage.swift new file mode 100644 index 000000000..ab430ffef --- /dev/null +++ b/Sources/ParseSwift/Storage/ParseStorage.swift @@ -0,0 +1,43 @@ +// +// File.swift +// +// +// Created by Pranjal Satija on 7/19/20. +// + +// MARK: ParseStorage +public struct ParseStorage { + public static var shared = ParseStorage() + + private var backingStore: PrimitiveObjectStore! + + mutating func use(_ store: PrimitiveObjectStore) { + self.backingStore = store + } + + private func requireBackingStore() { + guard backingStore != nil else { fatalError("You can't use ParseStorage without a backing store.") } + } + + enum Keys { + static let currentUser = "_currentUser" + } +} + +// MARK: PrimitiveObjectStore +extension ParseStorage: PrimitiveObjectStore { + public mutating func delete(valueFor key: String) throws { + requireBackingStore() + return try backingStore.delete(valueFor: key) + } + + public mutating func get(valueFor key: String) throws -> T? where T: Decodable { + requireBackingStore() + return try backingStore.get(valueFor: key) + } + + public mutating func set(_ object: T, for key: String) throws where T: Encodable { + requireBackingStore() + return try backingStore.set(object, for: key) + } +} diff --git a/Sources/ParseSwift/Storage/PrimitiveObjectStore.swift b/Sources/ParseSwift/Storage/PrimitiveObjectStore.swift new file mode 100644 index 000000000..42895c90d --- /dev/null +++ b/Sources/ParseSwift/Storage/PrimitiveObjectStore.swift @@ -0,0 +1,53 @@ +// +// File.swift +// +// +// Created by Pranjal Satija on 7/19/20. +// + +import Foundation + +// MARK: PrimitiveObjectStore +public protocol PrimitiveObjectStore { + mutating func delete(valueFor key: String) throws + mutating func get(valueFor key: String) throws -> T? + mutating func set(_ object: T, for key: String) throws +} + +/// A `PrimitiveObjectStore` that lives in memory for unit testing purposes. +/// It works by encoding / decoding all values just like a real `Codable` store would +/// but it stores all values as `Data` blobs in memory. +struct CodableInMemoryPrimitiveObjectStore: PrimitiveObjectStore { + var decoder = JSONDecoder() + var encoder = JSONEncoder() + var storage = [String: Data]() + + mutating func delete(valueFor key: String) throws { + storage[key] = nil + } + + mutating func get(valueFor key: String) throws -> T? where T: Decodable { + guard let data = storage[key] else { return nil } + return try decoder.decode(T.self, from: data) + } + + mutating func set(_ object: T, for key: String) throws where T: Encodable { + let data = try encoder.encode(object) + storage[key] = data + } +} + +// MARK: KeychainStore + PrimitiveObjectStore +extension KeychainStore: PrimitiveObjectStore { + func delete(valueFor key: String) throws { + _ = removeObject(forKey: key) + } + + func get(valueFor key: String) throws -> T? where T: Decodable { + return object(forKey: key) + } + + func set(_ object: T, for key: String) throws where T: Encodable { + _ = set(object: object, forKey: key) + } +} From bdfd7091d743ea17173132b9b790f8a1627afb5d Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Sun, 19 Jul 2020 22:57:59 -0400 Subject: [PATCH 07/30] simplify ParseEncoder --- Sources/ParseSwift/Coding/ParseCoding.swift | 17 ++-- Sources/ParseSwift/Coding/ParseEncoder.swift | 81 ++++---------------- 2 files changed, 20 insertions(+), 78 deletions(-) diff --git a/Sources/ParseSwift/Coding/ParseCoding.swift b/Sources/ParseSwift/Coding/ParseCoding.swift index 5ba4972ca..38c609ac0 100644 --- a/Sources/ParseSwift/Coding/ParseCoding.swift +++ b/Sources/ParseSwift/Coding/ParseCoding.swift @@ -17,19 +17,19 @@ extension ParseCoding { static func jsonEncoder() -> JSONEncoder { let encoder = JSONEncoder() - encoder.dateEncodingStrategy = jsonDateEncodingStrategy + encoder.dateEncodingStrategy = dateEncodingStrategy return encoder } static func jsonDecoder() -> JSONDecoder { let encoder = JSONDecoder() - encoder.dateDecodingStrategy = jsonDateDecodingStrategy + encoder.dateDecodingStrategy = dateDecodingStrategy return encoder } static func parseEncoder() -> ParseEncoder { let encoder = ParseEncoder() - encoder.dateEncodingStrategy = parseDateEncodingStrategy + encoder.dateEncodingStrategy = dateEncodingStrategy encoder.shouldEncodeKey = { (key, path) -> Bool in if path.count == 0 // top level && Self.forbiddenKeys.contains(key) { @@ -56,21 +56,14 @@ extension ParseCoding { return dateFormatter }() - static let jsonDateEncodingStrategy: JSONEncoder.DateEncodingStrategy = .custom({ (date, enc) in + static let dateEncodingStrategy: JSONEncoder.DateEncodingStrategy = .custom({ (date, enc) in var container = enc.container(keyedBy: DateEncodingKeys.self) try container.encode("Date", forKey: .type) let dateString = dateFormatter.string(from: date) try container.encode(dateString, forKey: .iso) }) - static let parseDateEncodingStrategy: ParseEncoder.DateEncodingStrategy = .custom({ (date, enc) in - var container = enc.container(keyedBy: DateEncodingKeys.self) - try container.encode("Date", forKey: .type) - let dateString = dateFormatter.string(from: date) - try container.encode(dateString, forKey: .iso) - }) - - static let jsonDateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .custom({ (dec) -> Date in + static let dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .custom({ (dec) -> Date in do { let container = try dec.singleValueContainer() let decodedString = try container.decode(String.self) diff --git a/Sources/ParseSwift/Coding/ParseEncoder.swift b/Sources/ParseSwift/Coding/ParseEncoder.swift index 9a17fe778..6a507aaf7 100644 --- a/Sources/ParseSwift/Coding/ParseEncoder.swift +++ b/Sources/ParseSwift/Coding/ParseEncoder.swift @@ -31,72 +31,10 @@ import Foundation // swiftlint:disable identifier_name open class ParseEncoder { - // MARK: Options - - /// The formatting of the output JSON data. - public struct OutputFormatting : OptionSet { - /// The format's default value. - public let rawValue: UInt - - /// Creates an OutputFormatting value with the given raw value. - public init(rawValue: UInt) { - self.rawValue = rawValue - } - - /// Produce human-readable JSON with indented output. - public static let prettyPrinted = OutputFormatting(rawValue: 1 << 0) - - /// Produce JSON with dictionary keys sorted in lexicographic order. - @available(OSX 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) - public static let sortedKeys = OutputFormatting(rawValue: 1 << 1) - } - - /// The strategy to use for encoding `Date` values. - public enum DateEncodingStrategy { - /// Defer to `Date` for choosing an encoding. This is the default strategy. - case deferredToDate - - /// Encode the `Date` as a UNIX timestamp (as a JSON number). - case secondsSince1970 - - /// Encode the `Date` as UNIX millisecond timestamp (as a JSON number). - case millisecondsSince1970 - - /// Encode the `Date` as an ISO-8601-formatted string (in RFC 3339 format). - @available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) - case iso8601 - - /// Encode the `Date` as a string formatted by the given formatter. - case formatted(DateFormatter) - - /// Encode the `Date` as a custom value encoded by the given closure. - /// - /// If the closure fails to encode a value into the given encoder, the encoder will encode an empty automatic container in its place. - case custom((Date, Encoder) throws -> Void) - } - - /// The strategy to use for encoding `Data` values. - public enum DataEncodingStrategy { - /// Defer to `Data` for choosing an encoding. - case deferredToData - - /// Encoded the `Data` as a Base64-encoded string. This is the default strategy. - case base64 - - /// Encode the `Data` as a custom value encoded by the given closure. - /// - /// If the closure fails to encode a value into the given encoder, the encoder will encode an empty automatic container in its place. - case custom((Data, Encoder) throws -> Void) - } - - /// The strategy to use for non-JSON-conforming floating-point values (IEEE 754 infinity and NaN). - public enum NonConformingFloatEncodingStrategy { - /// Throw upon encountering non-conforming values. This is the default strategy. - case `throw` - - /// Encode the values using the given representation strings. - case convertToString(positiveInfinity: String, negativeInfinity: String, nan: String) - } + public typealias DataEncodingStrategy = JSONEncoder.DataEncodingStrategy + public typealias DateEncodingStrategy = JSONEncoder.DateEncodingStrategy + public typealias OutputFormatting = JSONEncoder.OutputFormatting + public typealias NonConformingFloatEncodingStrategy = JSONEncoder.NonConformingFloatEncodingStrategy /// The output format to produce. Defaults to `[]`. open var outputFormatting: OutputFormatting = [] @@ -113,7 +51,9 @@ open class ParseEncoder { /// Contextual user-provided information for use during encoding. open var userInfo: [CodingUserInfoKey : Any] = [:] + /// Whether or not this encoder should encode a specific `CodingKey`. open var shouldEncodeKey: ((String, [CodingKey?]) -> Bool) = { (_, _) in true } + /// Options set on the top-level encoder to pass down the encoding hierarchy. internal struct _Options { let dateEncodingStrategy: DateEncodingStrategy @@ -662,6 +602,13 @@ extension _JSONEncoder { // We can pop because the closure encoded something. return self.storage.popContainer() + + @unknown default: + if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) { + return NSString(string: _iso8601Formatter.string(from: date)) + } else { + fatalError("ISO8601DateFormatter is unavailable on this platform.") + } } } @@ -686,6 +633,8 @@ extension _JSONEncoder { // We can pop because the closure encoded something. return self.storage.popContainer() + @unknown default: + return NSString(string: data.base64EncodedString()) } } From 18196012953b2c496420a7959b49de732748e9bc Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Mon, 20 Jul 2020 09:53:52 -0400 Subject: [PATCH 08/30] remove force unwrap --- Sources/ParseSwift/API/API+Commands.swift | 14 +++++++++++--- Sources/ParseSwift/API/API.swift | 6 ++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Sources/ParseSwift/API/API+Commands.swift b/Sources/ParseSwift/API/API+Commands.swift index c19c9a465..373ab771a 100644 --- a/Sources/ParseSwift/API/API+Commands.swift +++ b/Sources/ParseSwift/API/API+Commands.swift @@ -34,19 +34,27 @@ internal extension API { } public func execute(options: API.Options) throws -> U { + let url = ParseConfiguration.serverURL.appendingPathComponent(path.urlComponent) + + guard var components = URLComponents(url: url, resolvingAgainstBaseURL: false), + let componentsURL = components.url else { + throw Error.badRequest + } + let params = self.params?.getQueryItems() let headers = API.getHeaders(options: options) - let url = ParseConfiguration.serverURL.appendingPathComponent(path.urlComponent) - var components = URLComponents(url: url, resolvingAgainstBaseURL: false)! components.queryItems = params - var urlRequest = URLRequest(url: components.url!) + var urlRequest = URLRequest(url: componentsURL) urlRequest.allHTTPHeaderFields = headers + if let body = data { urlRequest.httpBody = body } + urlRequest.httpMethod = method.rawValue + let responseData = try URLSession.shared.syncDataTask(with: urlRequest) do { return try mapper(responseData) diff --git a/Sources/ParseSwift/API/API.swift b/Sources/ParseSwift/API/API.swift index 39c3b696f..3271a73b7 100644 --- a/Sources/ParseSwift/API/API.swift +++ b/Sources/ParseSwift/API/API.swift @@ -94,6 +94,12 @@ public struct API { } } +extension API { + public enum Error: Swift.Error { + case badRequest + } +} + internal extension Dictionary where Key == String, Value == String? { func getQueryItems() -> [URLQueryItem] { return map { (key, value) -> URLQueryItem in From d876bd1488778fc7464b67a58378079623eba417 Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Mon, 20 Jul 2020 10:32:04 -0400 Subject: [PATCH 09/30] use ParseError --- Sources/ParseSwift/API/API+Commands.swift | 4 ++-- Sources/ParseSwift/API/API.swift | 6 ------ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/Sources/ParseSwift/API/API+Commands.swift b/Sources/ParseSwift/API/API+Commands.swift index 373ab771a..be4595003 100644 --- a/Sources/ParseSwift/API/API+Commands.swift +++ b/Sources/ParseSwift/API/API+Commands.swift @@ -38,9 +38,9 @@ internal extension API { guard var components = URLComponents(url: url, resolvingAgainstBaseURL: false), let componentsURL = components.url else { - throw Error.badRequest + throw ParseError(code: .unknownError, message: "Invalid URL.") } - + let params = self.params?.getQueryItems() let headers = API.getHeaders(options: options) diff --git a/Sources/ParseSwift/API/API.swift b/Sources/ParseSwift/API/API.swift index 3271a73b7..39c3b696f 100644 --- a/Sources/ParseSwift/API/API.swift +++ b/Sources/ParseSwift/API/API.swift @@ -94,12 +94,6 @@ public struct API { } } -extension API { - public enum Error: Swift.Error { - case badRequest - } -} - internal extension Dictionary where Key == String, Value == String? { func getQueryItems() -> [URLQueryItem] { return map { (key, value) -> URLQueryItem in From b5c5259267ca141f8e7f8113c78f218a9a86ca36 Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Mon, 20 Jul 2020 19:21:47 -0400 Subject: [PATCH 10/30] retry build From 2cd23a9cb1639b02fc9d01212445d3dd7b484fcb Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Sun, 2 Aug 2020 22:11:41 -0400 Subject: [PATCH 11/30] finish merging --- ParseSwift.xcodeproj/project.pbxproj | 136 ++++++----- Sources/ParseSwift/API/API+Commands.swift | 10 +- Sources/ParseSwift/Coding/Extensions.swift | 4 +- Sources/ParseSwift/Coding/ParseCoding.swift | 5 +- .../Objects Protocols/ObjectType.swift | 220 ------------------ Sources/ParseSwift/Storage/ParseStorage.swift | 8 +- .../ParseObjectCommandTests.swift | 8 +- Tests/ParseSwiftTests/ParseSwiftTests.swift | 12 - .../ParseUserCommandTests.swift | 12 +- 9 files changed, 96 insertions(+), 319 deletions(-) delete mode 100644 Sources/ParseSwift/Objects Protocols/ObjectType.swift delete mode 100644 Tests/ParseSwiftTests/ParseSwiftTests.swift diff --git a/ParseSwift.xcodeproj/project.pbxproj b/ParseSwift.xcodeproj/project.pbxproj index e7e4ed5dc..037ad1387 100644 --- a/ParseSwift.xcodeproj/project.pbxproj +++ b/ParseSwift.xcodeproj/project.pbxproj @@ -32,7 +32,6 @@ 4AA807621F794242008CD551 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4AA807611F794242008CD551 /* Assets.xcassets */; }; 4AA807651F794242008CD551 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4AA807631F794242008CD551 /* LaunchScreen.storyboard */; }; 4AA807701F794C31008CD551 /* KeychainStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AA8076E1F794C1C008CD551 /* KeychainStoreTests.swift */; }; - 4AA807711F794C33008CD551 /* ParseSwiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AA8076F1F794C1C008CD551 /* ParseSwiftTests.swift */; }; 4AB8B4FE1F254AE10070F682 /* ParseSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4AB8B4F41F254AE10070F682 /* ParseSwift.framework */; }; 4AB8B5051F254AE10070F682 /* Parse.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AB8B4F71F254AE10070F682 /* Parse.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4AC397701F48778900DEA9D3 /* ACL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC3976F1F48778900DEA9D3 /* ACL.swift */; }; @@ -79,11 +78,11 @@ 912C9BCF24D3005D009947C3 /* ParseSwift_watchOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 912C9BCD24D3005D009947C3 /* ParseSwift_watchOS.h */; settings = {ATTRIBUTES = (Public, ); }; }; 912C9BDC24D3011F009947C3 /* ParseSwift_tvOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 912C9BDA24D3011F009947C3 /* ParseSwift_tvOS.h */; settings = {ATTRIBUTES = (Public, ); }; }; 912C9BE024D302B0009947C3 /* Parse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EE1F254B820063D731 /* Parse.swift */; }; - 912C9BE124D302B0009947C3 /* ObjectType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EC1F254B820063D731 /* ObjectType.swift */; }; - 912C9BE224D302B0009947C3 /* ObjectType+Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B8001F256B330063D731 /* ObjectType+Query.swift */; }; - 912C9BE324D302B0009947C3 /* ObjectType+Equatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14931F4A5E1E00A7A7EF /* ObjectType+Equatable.swift */; }; - 912C9BE424D302B0009947C3 /* ObjectType+Batch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14971F4A5F6900A7A7EF /* ObjectType+Batch.swift */; }; - 912C9BE524D302B0009947C3 /* UserType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA54E1F265A0D00628B17 /* UserType.swift */; }; + 912C9BE124D302B0009947C3 /* (null) in Sources */ = {isa = PBXBuildFile; }; + 912C9BE224D302B0009947C3 /* (null) in Sources */ = {isa = PBXBuildFile; }; + 912C9BE324D302B0009947C3 /* (null) in Sources */ = {isa = PBXBuildFile; }; + 912C9BE424D302B0009947C3 /* (null) in Sources */ = {isa = PBXBuildFile; }; + 912C9BE524D302B0009947C3 /* ParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA54E1F265A0D00628B17 /* ParseUser.swift */; }; 912C9BE624D302B0009947C3 /* ACL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC3976F1F48778900DEA9D3 /* ACL.swift */; }; 912C9BE724D302B0009947C3 /* ParseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AF85BD21F78011100665264 /* ParseError.swift */; }; 912C9BE824D302B0009947C3 /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7F01F254B820063D731 /* File.swift */; }; @@ -108,11 +107,11 @@ 912C9BFB24D302B0009947C3 /* SecureStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AA8074A1F7930E9008CD551 /* SecureStorage.swift */; }; 912C9BFC24D302B0009947C3 /* KeychainStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AA8074D1F7931B7008CD551 /* KeychainStore.swift */; }; 912C9BFD24D302B2009947C3 /* Parse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EE1F254B820063D731 /* Parse.swift */; }; - 912C9BFE24D302B2009947C3 /* ObjectType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EC1F254B820063D731 /* ObjectType.swift */; }; - 912C9BFF24D302B2009947C3 /* ObjectType+Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B8001F256B330063D731 /* ObjectType+Query.swift */; }; - 912C9C0024D302B2009947C3 /* ObjectType+Equatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14931F4A5E1E00A7A7EF /* ObjectType+Equatable.swift */; }; - 912C9C0124D302B2009947C3 /* ObjectType+Batch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14971F4A5F6900A7A7EF /* ObjectType+Batch.swift */; }; - 912C9C0224D302B2009947C3 /* UserType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA54E1F265A0D00628B17 /* UserType.swift */; }; + 912C9BFE24D302B2009947C3 /* (null) in Sources */ = {isa = PBXBuildFile; }; + 912C9BFF24D302B2009947C3 /* (null) in Sources */ = {isa = PBXBuildFile; }; + 912C9C0024D302B2009947C3 /* (null) in Sources */ = {isa = PBXBuildFile; }; + 912C9C0124D302B2009947C3 /* (null) in Sources */ = {isa = PBXBuildFile; }; + 912C9C0224D302B2009947C3 /* ParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA54E1F265A0D00628B17 /* ParseUser.swift */; }; 912C9C0324D302B2009947C3 /* ACL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC3976F1F48778900DEA9D3 /* ACL.swift */; }; 912C9C0424D302B2009947C3 /* ParseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AF85BD21F78011100665264 /* ParseError.swift */; }; 912C9C0524D302B2009947C3 /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7F01F254B820063D731 /* File.swift */; }; @@ -136,6 +135,22 @@ 912C9C1724D302B2009947C3 /* Responses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14951F4A5F2900A7A7EF /* Responses.swift */; }; 912C9C1824D302B2009947C3 /* SecureStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AA8074A1F7930E9008CD551 /* SecureStorage.swift */; }; 912C9C1924D302B2009947C3 /* KeychainStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AA8074D1F7931B7008CD551 /* KeychainStore.swift */; }; + F9D7984E24D7A8F100BEE62E /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7984C24D7A8F100BEE62E /* Extensions.swift */; }; + F9D7984F24D7A8F100BEE62E /* ParseCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7984D24D7A8F100BEE62E /* ParseCoding.swift */; }; + F9D7985424D7A91300BEE62E /* Fetchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985024D7A91300BEE62E /* Fetchable.swift */; }; + F9D7985524D7A91300BEE62E /* Queryable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985124D7A91300BEE62E /* Queryable.swift */; }; + F9D7985624D7A91300BEE62E /* Saveable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985224D7A91300BEE62E /* Saveable.swift */; }; + F9D7985724D7A91300BEE62E /* ParseObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985324D7A91300BEE62E /* ParseObject.swift */; }; + F9D7985A24D7A93000BEE62E /* NoBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985824D7A93000BEE62E /* NoBody.swift */; }; + F9D7985B24D7A93000BEE62E /* BaseParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985924D7A93000BEE62E /* BaseParseUser.swift */; }; + F9D7985C24D7A93700BEE62E /* BaseParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985924D7A93000BEE62E /* BaseParseUser.swift */; }; + F9D7985D24D7A93700BEE62E /* BaseParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985924D7A93000BEE62E /* BaseParseUser.swift */; }; + F9D7985E24D7A93700BEE62E /* BaseParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985924D7A93000BEE62E /* BaseParseUser.swift */; }; + F9D7985F24D7A93700BEE62E /* NoBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985824D7A93000BEE62E /* NoBody.swift */; }; + F9D7986024D7A93700BEE62E /* NoBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985824D7A93000BEE62E /* NoBody.swift */; }; + F9D7986124D7A93700BEE62E /* NoBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985824D7A93000BEE62E /* NoBody.swift */; }; + F9D7986424D7A95800BEE62E /* ParseStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7986224D7A95700BEE62E /* ParseStorage.swift */; }; + F9D7986524D7A95800BEE62E /* PrimitiveObjectStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7986324D7A95800BEE62E /* PrimitiveObjectStore.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -178,7 +193,6 @@ 4AA807661F794242008CD551 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4AA8076D1F794C1C008CD551 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4AA8076E1F794C1C008CD551 /* KeychainStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainStoreTests.swift; sourceTree = ""; }; - 4AA8076F1F794C1C008CD551 /* ParseSwiftTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseSwiftTests.swift; sourceTree = ""; }; 4AB8B4F41F254AE10070F682 /* ParseSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ParseSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4AB8B4F71F254AE10070F682 /* Parse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Parse.h; sourceTree = ""; }; 4AB8B4F81F254AE10070F682 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -213,6 +227,16 @@ 912C9BD824D3011F009947C3 /* ParseSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ParseSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 912C9BDA24D3011F009947C3 /* ParseSwift_tvOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ParseSwift_tvOS.h; sourceTree = ""; }; 912C9BDB24D3011F009947C3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + F9D7984C24D7A8F100BEE62E /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; + F9D7984D24D7A8F100BEE62E /* ParseCoding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseCoding.swift; sourceTree = ""; }; + F9D7985024D7A91300BEE62E /* Fetchable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Fetchable.swift; sourceTree = ""; }; + F9D7985124D7A91300BEE62E /* Queryable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Queryable.swift; sourceTree = ""; }; + F9D7985224D7A91300BEE62E /* Saveable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Saveable.swift; sourceTree = ""; }; + F9D7985324D7A91300BEE62E /* ParseObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseObject.swift; sourceTree = ""; }; + F9D7985824D7A93000BEE62E /* NoBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoBody.swift; sourceTree = ""; }; + F9D7985924D7A93000BEE62E /* BaseParseUser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseParseUser.swift; sourceTree = ""; }; + F9D7986224D7A95700BEE62E /* ParseStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseStorage.swift; sourceTree = ""; }; + F9D7986324D7A95800BEE62E /* PrimitiveObjectStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrimitiveObjectStore.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -291,11 +315,11 @@ isa = PBXGroup; children = ( 4AC3976F1F48778900DEA9D3 /* ACL.swift */, - F980C99824C52E0200262E4F /* BaseParseUser.swift */, - 4AF85BD21F78011100665264 /* ParseError.swift */, + F9D7985924D7A93000BEE62E /* BaseParseUser.swift */, 4A82B7F01F254B820063D731 /* File.swift */, 4A82B7ED1F254B820063D731 /* GeoPoint.swift */, - F92B578C24C3F0F300A43E8D /* NoBody.swift */, + F9D7985824D7A93000BEE62E /* NoBody.swift */, + 4AF85BD21F78011100665264 /* ParseError.swift */, 4A82B7F11F254B820063D731 /* Pointer.swift */, 4A82B7FE1F256A8F0063D731 /* Query.swift */, ); @@ -320,8 +344,8 @@ isa = PBXGroup; children = ( 4AA8074D1F7931B7008CD551 /* KeychainStore.swift */, - F980C99A24C52E1900262E4F /* ParseStorage.swift */, - F980C99B24C52E1900262E4F /* PrimitiveObjectStore.swift */, + F9D7986224D7A95700BEE62E /* ParseStorage.swift */, + F9D7986324D7A95800BEE62E /* PrimitiveObjectStore.swift */, 4AA8074A1F7930E9008CD551 /* SecureStorage.swift */, ); path = Storage; @@ -345,11 +369,9 @@ 7FFF552A2217E729007C3B4E /* AnyCodableTests */, 4AA8076D1F794C1C008CD551 /* Info.plist */, 4AA8076E1F794C1C008CD551 /* KeychainStoreTests.swift */, - 4AA8076F1F794C1C008CD551 /* ParseSwiftTests.swift */, 911DB13524C4FC100027F3C7 /* ParseObjectCommandTests.swift */, 70E5503D24C7A54C00F6D8D2 /* ParseUserCommandTests.swift */, 911DB12D24C4837E0027F3C7 /* APICommandTests.swift */, - 911DB13424C4FBD20027F3C7 /* Other */, 911DB12A24C3F7260027F3C7 /* NetworkMocking */, ); path = ParseSwiftTests; @@ -402,11 +424,11 @@ 4AC397761F4895A200DEA9D3 /* Objects */ = { isa = PBXGroup; children = ( - F927E37B24C3D1FD00F8A143 /* Fetchable.swift */, - F927E37824C3D19900F8A143 /* ParseObject.swift */, - F92B578924C3F09600A43E8D /* Queryable.swift */, - F92B578624C3F02D00A43E8D /* Saveable.swift */, + F9D7985024D7A91300BEE62E /* Fetchable.swift */, + F9D7985324D7A91300BEE62E /* ParseObject.swift */, 4AEBA54E1F265A0D00628B17 /* ParseUser.swift */, + F9D7985124D7A91300BEE62E /* Queryable.swift */, + F9D7985224D7A91300BEE62E /* Saveable.swift */, ); path = Objects; sourceTree = ""; @@ -437,8 +459,8 @@ 709075C424B9117400B95310 /* AnyCodable.swift */, 709075C524B9117500B95310 /* AnyDecodable.swift */, 709075C624B9117500B95310 /* AnyEncodable.swift */, - F980C99224C52DD800262E4F /* Extensions.swift */, - F980C99324C52DD900262E4F /* ParseCoding.swift */, + F9D7984C24D7A8F100BEE62E /* Extensions.swift */, + F9D7984D24D7A8F100BEE62E /* ParseCoding.swift */, 4A2D8C801F48B3A900EE1FCC /* ParseEncoder.swift */, ); path = Coding; @@ -463,13 +485,6 @@ path = NetworkMocking; sourceTree = ""; }; - 911DB13424C4FBD20027F3C7 /* Other */ = { - isa = PBXGroup; - children = ( - ); - path = Other; - sourceTree = ""; - }; 912C9BCC24D3005D009947C3 /* ParseSwift-watchOS */ = { isa = PBXGroup; children = ( @@ -790,40 +805,40 @@ buildActionMask = 2147483647; files = ( 4A2F14961F4A5F2900A7A7EF /* Responses.swift in Sources */, + F9D7984E24D7A8F100BEE62E /* Extensions.swift in Sources */, 709075C724B9117500B95310 /* AnyCodable.swift in Sources */, 4AC397741F488FF900DEA9D3 /* API.swift in Sources */, 4A82B7F51F254CCE0063D731 /* GeoPoint.swift in Sources */, 4AA8074B1F7930E9008CD551 /* SecureStorage.swift in Sources */, 4A82B7F61F254CCE0063D731 /* Parse.swift in Sources */, 4AEBA54F1F265A0D00628B17 /* ParseUser.swift in Sources */, - F92B578D24C3F0F300A43E8D /* NoBody.swift in Sources */, - F927E37C24C3D1FD00F8A143 /* Fetchable.swift in Sources */, 4A99A4691F2650CA00D72A59 /* ParseMutationContainer.swift in Sources */, 4AC397701F48778900DEA9D3 /* ACL.swift in Sources */, 4A2D8C811F48B3A900EE1FCC /* ParseEncoder.swift in Sources */, 4A99A46E1F26512100D72A59 /* IncrementOperation.swift in Sources */, 4A82B7FF1F256A8F0063D731 /* Query.swift in Sources */, 4AF85BD81F78144900665264 /* URLSession+sync.swift in Sources */, - F927E37924C3D19900F8A143 /* ParseObject.swift in Sources */, 709075CB24B9117500B95310 /* AnyEncodable.swift in Sources */, 4A82B7F41F254CCE0063D731 /* File.swift in Sources */, + F9D7985424D7A91300BEE62E /* Fetchable.swift in Sources */, 4AF85BD31F78011100665264 /* ParseError.swift in Sources */, 4AF85BDA1F781ED000665264 /* Asynchronous.swift in Sources */, - F92B578724C3F02D00A43E8D /* Saveable.swift in Sources */, 4AA8074E1F7931B7008CD551 /* KeychainStore.swift in Sources */, + F9D7985524D7A91300BEE62E /* Queryable.swift in Sources */, 4AC397721F488F9E00DEA9D3 /* BatchUtils.swift in Sources */, - F92B578A24C3F09600A43E8D /* Queryable.swift in Sources */, 4AEBA54D1F26523800628B17 /* DeleteOperation.swift in Sources */, 4AF85BDD1F783B9800665264 /* API+Commands.swift in Sources */, + F9D7985624D7A91300BEE62E /* Saveable.swift in Sources */, 4A82B7F81F254CCE0063D731 /* Pointer.swift in Sources */, - F980C99C24C52E1900262E4F /* ParseStorage.swift in Sources */, + F9D7985A24D7A93000BEE62E /* NoBody.swift in Sources */, + F9D7986424D7A95800BEE62E /* ParseStorage.swift in Sources */, + F9D7984F24D7A8F100BEE62E /* ParseCoding.swift in Sources */, 709075C924B9117500B95310 /* AnyDecodable.swift in Sources */, - F980C99524C52DD900262E4F /* ParseCoding.swift in Sources */, - F980C99D24C52E1900262E4F /* PrimitiveObjectStore.swift in Sources */, - F980C99924C52E0200262E4F /* BaseParseUser.swift in Sources */, + F9D7986524D7A95800BEE62E /* PrimitiveObjectStore.swift in Sources */, + F9D7985B24D7A93000BEE62E /* BaseParseUser.swift in Sources */, 4AEBA5491F26519B00628B17 /* AddOperation.swift in Sources */, 4A99A46C1F2650FF00D72A59 /* AddUniqueOperation.swift in Sources */, - F980C99424C52DD900262E4F /* Extensions.swift in Sources */, + F9D7985724D7A91300BEE62E /* ParseObject.swift in Sources */, 4AEBA54B1F2651D900628B17 /* RemoveOperation.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -839,7 +854,6 @@ 7FFF55302217E72A007C3B4E /* AnyDecodableTests.swift in Sources */, 7FFF552F2217E72A007C3B4E /* AnyCodableTests.swift in Sources */, 4AA807701F794C31008CD551 /* KeychainStoreTests.swift in Sources */, - 4AA807711F794C33008CD551 /* ParseSwiftTests.swift in Sources */, 70E5503E24C7A54C00F6D8D2 /* ParseUserCommandTests.swift in Sources */, 911DB13324C494390027F3C7 /* MockURLProtocol.swift in Sources */, ); @@ -849,41 +863,33 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - F980C99E24C52E1D00262E4F /* PrimitiveObjectStore.swift in Sources */, 709075C824B9117500B95310 /* AnyCodable.swift in Sources */, 4AFDA7301F26DAE1002AE4FC /* DeleteOperation.swift in Sources */, - F980C9A024C5395400262E4F /* BaseParseUser.swift in Sources */, 4AFDA7341F26DAE1002AE4FC /* Pointer.swift in Sources */, + F9D7985D24D7A93700BEE62E /* BaseParseUser.swift in Sources */, 4AA8074C1F7930E9008CD551 /* SecureStorage.swift in Sources */, 4A6511501F48E400005237DF /* BatchUtils.swift in Sources */, 4AFDA72A1F26DAE1002AE4FC /* Parse.swift in Sources */, - F92B578E24C3F0F300A43E8D /* NoBody.swift in Sources */, - F927E37D24C3D1FD00F8A143 /* Fetchable.swift in Sources */, 4AFDA7351F26DAE1002AE4FC /* Query.swift in Sources */, 4A2F14991F4A5FB500A7A7EF /* Responses.swift in Sources */, 4A65114F1F48E3F3005237DF /* ParseEncoder.swift in Sources */, 4AFDA72E1F26DAE1002AE4FC /* AddOperation.swift in Sources */, 4AFDA7311F26DAE1002AE4FC /* AddUniqueOperation.swift in Sources */, 4AF85BD91F78145C00665264 /* URLSession+sync.swift in Sources */, - F927E37A24C3D19900F8A143 /* ParseObject.swift in Sources */, 709075CC24B9117500B95310 /* AnyEncodable.swift in Sources */, 4A6511521F48E406005237DF /* GeoPoint.swift in Sources */, 4AF85BD61F7803C100665264 /* ParseError.swift in Sources */, 4AF85BDB1F781ED100665264 /* Asynchronous.swift in Sources */, - F92B578824C3F02D00A43E8D /* Saveable.swift in Sources */, 4AA8074F1F7931B7008CD551 /* KeychainStore.swift in Sources */, 4AFDA7331F26DAE1002AE4FC /* File.swift in Sources */, 4A6511531F48E410005237DF /* API.swift in Sources */, - F92B578B24C3F09600A43E8D /* Queryable.swift in Sources */, 4AFDA7321F26DAE1002AE4FC /* IncrementOperation.swift in Sources */, 4AF85BDE1F783BB400665264 /* API+Commands.swift in Sources */, - F980C99F24C52E1D00262E4F /* ParseStorage.swift in Sources */, + F9D7986024D7A93700BEE62E /* NoBody.swift in Sources */, 4AFDA72D1F26DAE1002AE4FC /* ParseMutationContainer.swift in Sources */, 709075CA24B9117500B95310 /* AnyDecodable.swift in Sources */, - F980C99724C52DE100262E4F /* ParseCoding.swift in Sources */, 4AFDA72C1F26DAE1002AE4FC /* ParseUser.swift in Sources */, 4A6511511F48E406005237DF /* ACL.swift in Sources */, - F980C99624C52DE100262E4F /* Extensions.swift in Sources */, 4AFDA72F1F26DAE1002AE4FC /* RemoveOperation.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -898,27 +904,29 @@ 912C9C0924D302B2009947C3 /* AnyCodable.swift in Sources */, 912C9C0B24D302B2009947C3 /* AnyEncodable.swift in Sources */, 912C9C0424D302B2009947C3 /* ParseError.swift in Sources */, - 912C9BFE24D302B2009947C3 /* ObjectType.swift in Sources */, + 912C9BFE24D302B2009947C3 /* (null) in Sources */, 912C9C1624D302B2009947C3 /* URLSession+sync.swift in Sources */, + F9D7985F24D7A93700BEE62E /* NoBody.swift in Sources */, 912C9C0724D302B2009947C3 /* Pointer.swift in Sources */, 912C9C1124D302B2009947C3 /* AddUniqueOperation.swift in Sources */, - 912C9C0124D302B2009947C3 /* ObjectType+Batch.swift in Sources */, + 912C9C0124D302B2009947C3 /* (null) in Sources */, 912C9C0824D302B2009947C3 /* Query.swift in Sources */, 912C9C0E24D302B2009947C3 /* AddOperation.swift in Sources */, - 912C9C0224D302B2009947C3 /* UserType.swift in Sources */, + 912C9C0224D302B2009947C3 /* ParseUser.swift in Sources */, 912C9C1524D302B2009947C3 /* BatchUtils.swift in Sources */, 912C9C0F24D302B2009947C3 /* RemoveOperation.swift in Sources */, 912C9C1424D302B2009947C3 /* API+Commands.swift in Sources */, 912C9C0C24D302B2009947C3 /* ParseEncoder.swift in Sources */, 912C9C0624D302B2009947C3 /* GeoPoint.swift in Sources */, - 912C9C0024D302B2009947C3 /* ObjectType+Equatable.swift in Sources */, + 912C9C0024D302B2009947C3 /* (null) in Sources */, 912C9C1324D302B2009947C3 /* API.swift in Sources */, 912C9C0324D302B2009947C3 /* ACL.swift in Sources */, - 912C9BFF24D302B2009947C3 /* ObjectType+Query.swift in Sources */, + 912C9BFF24D302B2009947C3 /* (null) in Sources */, 912C9C0524D302B2009947C3 /* File.swift in Sources */, 912C9C0A24D302B2009947C3 /* AnyDecodable.swift in Sources */, 912C9C1224D302B2009947C3 /* IncrementOperation.swift in Sources */, 912C9BFD24D302B2009947C3 /* Parse.swift in Sources */, + F9D7985C24D7A93700BEE62E /* BaseParseUser.swift in Sources */, 912C9C0D24D302B2009947C3 /* ParseMutationContainer.swift in Sources */, 912C9C1924D302B2009947C3 /* KeychainStore.swift in Sources */, ); @@ -934,27 +942,29 @@ 912C9BEC24D302B0009947C3 /* AnyCodable.swift in Sources */, 912C9BEE24D302B0009947C3 /* AnyEncodable.swift in Sources */, 912C9BE724D302B0009947C3 /* ParseError.swift in Sources */, - 912C9BE124D302B0009947C3 /* ObjectType.swift in Sources */, + 912C9BE124D302B0009947C3 /* (null) in Sources */, 912C9BF924D302B0009947C3 /* URLSession+sync.swift in Sources */, + F9D7986124D7A93700BEE62E /* NoBody.swift in Sources */, 912C9BEA24D302B0009947C3 /* Pointer.swift in Sources */, 912C9BF424D302B0009947C3 /* AddUniqueOperation.swift in Sources */, - 912C9BE424D302B0009947C3 /* ObjectType+Batch.swift in Sources */, + 912C9BE424D302B0009947C3 /* (null) in Sources */, 912C9BEB24D302B0009947C3 /* Query.swift in Sources */, 912C9BF124D302B0009947C3 /* AddOperation.swift in Sources */, - 912C9BE524D302B0009947C3 /* UserType.swift in Sources */, + 912C9BE524D302B0009947C3 /* ParseUser.swift in Sources */, 912C9BF824D302B0009947C3 /* BatchUtils.swift in Sources */, 912C9BF224D302B0009947C3 /* RemoveOperation.swift in Sources */, 912C9BF724D302B0009947C3 /* API+Commands.swift in Sources */, 912C9BEF24D302B0009947C3 /* ParseEncoder.swift in Sources */, 912C9BE924D302B0009947C3 /* GeoPoint.swift in Sources */, - 912C9BE324D302B0009947C3 /* ObjectType+Equatable.swift in Sources */, + 912C9BE324D302B0009947C3 /* (null) in Sources */, 912C9BF624D302B0009947C3 /* API.swift in Sources */, 912C9BE624D302B0009947C3 /* ACL.swift in Sources */, - 912C9BE224D302B0009947C3 /* ObjectType+Query.swift in Sources */, + 912C9BE224D302B0009947C3 /* (null) in Sources */, 912C9BE824D302B0009947C3 /* File.swift in Sources */, 912C9BED24D302B0009947C3 /* AnyDecodable.swift in Sources */, 912C9BF524D302B0009947C3 /* IncrementOperation.swift in Sources */, 912C9BE024D302B0009947C3 /* Parse.swift in Sources */, + F9D7985E24D7A93700BEE62E /* BaseParseUser.swift in Sources */, 912C9BF024D302B0009947C3 /* ParseMutationContainer.swift in Sources */, 912C9BFC24D302B0009947C3 /* KeychainStore.swift in Sources */, ); diff --git a/Sources/ParseSwift/API/API+Commands.swift b/Sources/ParseSwift/API/API+Commands.swift index fc4574632..9df622c42 100644 --- a/Sources/ParseSwift/API/API+Commands.swift +++ b/Sources/ParseSwift/API/API+Commands.swift @@ -40,7 +40,7 @@ internal extension API { let componentsURL = components.url else { throw ParseError(code: .unknownError, message: "Invalid URL.") } - + let params = self.params?.getQueryItems() let headers = API.getHeaders(options: options) @@ -59,16 +59,10 @@ internal extension API { return try mapper(responseData) } catch { do { - throw try getDecoder().decode(ParseError.self, from: responseData) + throw try ParseCoding.jsonDecoder().decode(ParseError.self, from: responseData) } catch { throw ParseError(code: .unknownError, message: "cannot decode response: \(error)") } - - let responseData = try URLSession.shared.syncDataTask(with: urlRequest) - do { - return try mapper(responseData) - } catch _ { - throw try ParseCoding.jsonDecoder().decode(ParseError.self, from: responseData) } } diff --git a/Sources/ParseSwift/Coding/Extensions.swift b/Sources/ParseSwift/Coding/Extensions.swift index c12b79755..205d6b8dd 100644 --- a/Sources/ParseSwift/Coding/Extensions.swift +++ b/Sources/ParseSwift/Coding/Extensions.swift @@ -31,7 +31,7 @@ extension JSONEncoder { // MARK: ParseObject internal extension ParseObject { - func getEncoder() -> ParseEncoder { - return ParseCoding.parseEncoder() + func getEncoder(skipKeys: Bool = true) -> ParseEncoder { + return ParseCoding.parseEncoder(skipKeys: skipKeys) } } diff --git a/Sources/ParseSwift/Coding/ParseCoding.swift b/Sources/ParseSwift/Coding/ParseCoding.swift index 38c609ac0..1fdba865e 100644 --- a/Sources/ParseSwift/Coding/ParseCoding.swift +++ b/Sources/ParseSwift/Coding/ParseCoding.swift @@ -27,14 +27,15 @@ extension ParseCoding { return encoder } - static func parseEncoder() -> ParseEncoder { + static func parseEncoder(skipKeys: Bool = true) -> ParseEncoder { let encoder = ParseEncoder() encoder.dateEncodingStrategy = dateEncodingStrategy encoder.shouldEncodeKey = { (key, path) -> Bool in - if path.count == 0 // top level + if skipKeys && path.count == 0 // top level && Self.forbiddenKeys.contains(key) { return false } + return true } diff --git a/Sources/ParseSwift/Objects Protocols/ObjectType.swift b/Sources/ParseSwift/Objects Protocols/ObjectType.swift deleted file mode 100644 index 1260fa383..000000000 --- a/Sources/ParseSwift/Objects Protocols/ObjectType.swift +++ /dev/null @@ -1,220 +0,0 @@ -// -// ParseObjectType.swift -// ParseSwift -// -// Created by Florent Vilmart on 17-07-24. -// Copyright © 2017 Parse. All rights reserved. -// - -import Foundation - -public struct NoBody: Codable {} - -public protocol Saving: Codable { - associatedtype SavingType - func save(options: API.Options) throws -> SavingType - func save() throws -> SavingType -} - -extension Saving { - public func save() throws -> SavingType { - return try save(options: []) - } -} - -public protocol Fetching: Codable { - associatedtype FetchingType - func fetch(options: API.Options) throws -> FetchingType - func fetch() throws -> FetchingType -} - -extension Fetching { - public func fetch() throws -> FetchingType { - return try fetch(options: []) - } -} - -public protocol ObjectType: Fetching, Saving, CustomDebugStringConvertible, Equatable { - static var className: String { get } - var objectId: String? { get set } - var createdAt: Date? { get set } - var updatedAt: Date? { get set } - var ACL: ACL? { get set } -} - -internal extension ObjectType { - func getEncoder() -> ParseEncoder { - return getParseEncoder() - } - - func getTestDecoder() -> JSONDecoder { - return getDecoder() - } - - func getEncoderWithoutSkippingKeys() -> ParseEncoder { - return getParseEncoderWithoutSkippingKeys() - } -} - -extension ObjectType { - // Parse ClassName inference - public static var className: String { - let classType = "\(type(of: self))" - return classType.components(separatedBy: ".").first! // strip .Type - } - public var className: String { - return Self.className - } -} - -extension ObjectType { - public var debugDescription: String { - guard let descriptionData = try? getJSONEncoder().encode(self), - let descriptionString = String(data: descriptionData, encoding: .utf8) else { - return "\(className) ()" - } - return "\(className) (\(descriptionString))" - } -} - -public extension ObjectType { - func toPointer() -> Pointer { - return Pointer(self) - } -} - -enum DateEncodingKeys: String, CodingKey { - case iso - case type = "__type" -} - -let dateFormatter: DateFormatter = { - var dateFormatter = DateFormatter() - dateFormatter.locale = Locale(identifier: "") - dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" - return dateFormatter -}() - -let parseDateEncodingStrategy: ParseEncoder.DateEncodingStrategy = .custom({ (date, enc) in - var container = enc.container(keyedBy: DateEncodingKeys.self) - try container.encode("Date", forKey: .type) - let dateString = dateFormatter.string(from: date) - try container.encode(dateString, forKey: .iso) -}) - -let dateEncodingStrategy: JSONEncoder.DateEncodingStrategy = .custom({ (date, enc) in - var container = enc.container(keyedBy: DateEncodingKeys.self) - try container.encode("Date", forKey: .type) - let dateString = dateFormatter.string(from: date) - try container.encode(dateString, forKey: .iso) -}) - -internal extension Date { - func parseFormatted() -> String { - return dateFormatter.string(from: self) - } - var parseRepresentation: [String: String] { - return ["__type": "Date", "iso": parseFormatted()] - } -} - -let dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .custom({ (dec) -> Date in - do { - let container = try dec.singleValueContainer() - let decodedString = try container.decode(String.self) - return dateFormatter.date(from: decodedString)! - } catch let error { - let container = try dec.container(keyedBy: DateEncodingKeys.self) - if let decoded = try container.decodeIfPresent(String.self, forKey: .iso) { - return dateFormatter.date(from: decoded)! - } - } - throw ParseError(code: .unknownError, message: "unable to decode") -}) - -func getJSONEncoder() -> JSONEncoder { - let encoder = JSONEncoder() - encoder.dateEncodingStrategy = dateEncodingStrategy - return encoder -} - -private let forbiddenKeys = ["createdAt", "updatedAt", "objectId", "className"] - -func getParseEncoder() -> ParseEncoder { - return getParseEncoder(skipKeys: true) -} - -func getParseEncoderWithoutSkippingKeys() -> ParseEncoder { - return getParseEncoder(skipKeys: false) -} - -internal func getParseEncoder(skipKeys: Bool) -> ParseEncoder { - let encoder = ParseEncoder() - encoder.dateEncodingStrategy = parseDateEncodingStrategy - encoder.shouldEncodeKey = { (key, path) -> Bool in - if path.count == 0 // top level - && forbiddenKeys.firstIndex(of: key) != nil - && skipKeys { - return false - } - return true - } - return encoder -} - -extension JSONEncoder { - func encodeAsString(_ value: T) throws -> String where T: Encodable { - guard let string = String(data: try encode(value), encoding: .utf8) else { - throw ParseError(code: .unknownError, message: "Unable to encode object...") - } - return string - } -} - -func getDecoder() -> JSONDecoder { - let encoder = JSONDecoder() - encoder.dateDecodingStrategy = dateDecodingStrategy - return encoder -} - -public extension ObjectType { - func save(options: API.Options) throws -> Self { - return try saveCommand().execute(options: options) - } - - func fetch(options: API.Options) throws -> Self { - return try fetchCommand().execute(options: options) - } - - internal func saveCommand() -> API.Command { - return API.Command.saveCommand(self) - } - - internal func fetchCommand() throws -> API.Command { - return try API.Command.fetchCommand(self) - } -} - -extension ObjectType { - var endpoint: API.Endpoint { - if let objectId = objectId { - return .object(className: className, objectId: objectId) - } - return .objects(className: className) - } - - var isSaved: Bool { - return objectId != nil - } -} - -public struct FindResult: Decodable where T: ObjectType { - let results: [T] - let count: Int? -} - -public extension ObjectType { - var mutationContainer: ParseMutationContainer { - return ParseMutationContainer(target: self) - } -} diff --git a/Sources/ParseSwift/Storage/ParseStorage.swift b/Sources/ParseSwift/Storage/ParseStorage.swift index ab430ffef..962032169 100644 --- a/Sources/ParseSwift/Storage/ParseStorage.swift +++ b/Sources/ParseSwift/Storage/ParseStorage.swift @@ -15,8 +15,12 @@ public struct ParseStorage { self.backingStore = store } - private func requireBackingStore() { - guard backingStore != nil else { fatalError("You can't use ParseStorage without a backing store.") } + private mutating func requireBackingStore() { + guard backingStore != nil else { + print("You can't use ParseStorage without a backing store. An in-memory store is being used as a fallback.") + backingStore = CodableInMemoryPrimitiveObjectStore() + return + } } enum Keys { diff --git a/Tests/ParseSwiftTests/ParseObjectCommandTests.swift b/Tests/ParseSwiftTests/ParseObjectCommandTests.swift index 922118087..ef998b1bb 100644 --- a/Tests/ParseSwiftTests/ParseObjectCommandTests.swift +++ b/Tests/ParseSwiftTests/ParseObjectCommandTests.swift @@ -12,7 +12,7 @@ import XCTest class ParseObjectCommandTests: XCTestCase { - struct GameScore: ParseSwift.ObjectType { + struct GameScore: ParseObject { //: Those are required for Object var objectId: String? var createdAt: Date? @@ -75,7 +75,7 @@ class ParseObjectCommandTests: XCTestCase { MockURLProtocol.mockRequests { _ in do { - let encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(scoreOnServer) + let encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(scoreOnServer) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil @@ -141,7 +141,7 @@ class ParseObjectCommandTests: XCTestCase { MockURLProtocol.mockRequests { _ in do { - let encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(scoreOnServer) + let encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(scoreOnServer) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil @@ -180,7 +180,7 @@ class ParseObjectCommandTests: XCTestCase { MockURLProtocol.mockRequests { _ in do { - let encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(scoreOnServer) + let encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(scoreOnServer) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil diff --git a/Tests/ParseSwiftTests/ParseSwiftTests.swift b/Tests/ParseSwiftTests/ParseSwiftTests.swift deleted file mode 100644 index a8865d549..000000000 --- a/Tests/ParseSwiftTests/ParseSwiftTests.swift +++ /dev/null @@ -1,12 +0,0 @@ -// -// ParseTests.swift -// ParseTests -// -// Created by Florent Vilmart on 17-07-23. -// Copyright © 2017 Parse. All rights reserved. -// - -import XCTest -@testable import ParseSwift - -class ParseTests: XCTestCase {} diff --git a/Tests/ParseSwiftTests/ParseUserCommandTests.swift b/Tests/ParseSwiftTests/ParseUserCommandTests.swift index 6339a4afd..a194dfa6e 100644 --- a/Tests/ParseSwiftTests/ParseUserCommandTests.swift +++ b/Tests/ParseSwiftTests/ParseUserCommandTests.swift @@ -12,7 +12,7 @@ import XCTest class ParseUserCommandTests: XCTestCase { - struct User: ParseSwift.UserType { + struct User: ParseUser { //: Those are required for Object var objectId: String? var createdAt: Date? @@ -28,7 +28,7 @@ class ParseUserCommandTests: XCTestCase { var customKey: String? } - struct LoginSignupResponse: ParseSwift.UserType { + struct LoginSignupResponse: ParseUser { var objectId: String? var createdAt: Date? var sessionToken: String @@ -103,7 +103,7 @@ class ParseUserCommandTests: XCTestCase { MockURLProtocol.mockRequests { _ in do { - let encoded = try userOnServer.getEncoderWithoutSkippingKeys().encode(userOnServer) + let encoded = try userOnServer.getEncoder(skipKeys: false).encode(userOnServer) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil @@ -171,7 +171,7 @@ class ParseUserCommandTests: XCTestCase { MockURLProtocol.mockRequests { _ in do { - let encoded = try userOnServer.getEncoderWithoutSkippingKeys().encode(userOnServer) + let encoded = try userOnServer.getEncoder(skipKeys: false).encode(userOnServer) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil @@ -223,7 +223,7 @@ class ParseUserCommandTests: XCTestCase { MockURLProtocol.mockRequests { _ in do { - let encoded = try loginResponse.getEncoderWithoutSkippingKeys().encode(loginResponse) + let encoded = try loginResponse.getEncoder(skipKeys: false).encode(loginResponse) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil @@ -252,7 +252,7 @@ class ParseUserCommandTests: XCTestCase { MockURLProtocol.mockRequests { _ in do { - let encoded = try loginResponse.getEncoderWithoutSkippingKeys().encode(loginResponse) + let encoded = try loginResponse.getEncoder(skipKeys: false).encode(loginResponse) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil From 1070fe9b3a8598c3854ac773adc2b2d655297072 Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Mon, 3 Aug 2020 12:37:20 -0500 Subject: [PATCH 12/30] add hasSameObjectId --- Sources/ParseSwift/Objects/ParseObject.swift | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/Sources/ParseSwift/Objects/ParseObject.swift b/Sources/ParseSwift/Objects/ParseObject.swift index ff5cd5b2c..85d894189 100644 --- a/Sources/ParseSwift/Objects/ParseObject.swift +++ b/Sources/ParseSwift/Objects/ParseObject.swift @@ -9,7 +9,7 @@ import Foundation // MARK: ParseObject -public protocol ParseObject: Fetchable, Saveable, CustomDebugStringConvertible, Equatable { +public protocol ParseObject: Fetchable, Saveable, CustomDebugStringConvertible { static var className: String { get } var objectId: String? { get set } @@ -28,6 +28,10 @@ extension ParseObject { public var className: String { return Self.className } + + public func hasSameObjectId(as other: T) -> Bool { + return other.className == className && other.objectId == objectId && objectId != nil + } } // MARK: Batch Support @@ -73,16 +77,6 @@ extension ParseObject { } } -// MARK: Equatable -public func == (lhs: T?, rhs: T?) -> Bool where T: ParseObject { - guard let lhs = lhs, let rhs = rhs else { return false } - return lhs == rhs -} - -public func == (lhs: T, rhs: T) -> Bool where T: ParseObject { - return lhs.className == rhs.className && rhs.objectId == lhs.objectId -} - // MARK: Fetchable extension ParseObject { public func fetch(options: API.Options) throws -> Self { From f209e2e5d7a93a6075f169ec62bc35b1b947e071 Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Mon, 3 Aug 2020 17:12:19 -0500 Subject: [PATCH 13/30] add rough NewParseEncoder --- ParseSwift.xcodeproj/project.pbxproj | 8 + .../ParseSwift/Coding/NewParseEncoder.swift | 161 ++++++++++++++++++ .../NewParseEncoderTests.swift | 44 +++++ 3 files changed, 213 insertions(+) create mode 100644 Sources/ParseSwift/Coding/NewParseEncoder.swift create mode 100644 Tests/ParseSwiftTests/NewParseEncoderTests.swift diff --git a/ParseSwift.xcodeproj/project.pbxproj b/ParseSwift.xcodeproj/project.pbxproj index 037ad1387..25182ee41 100644 --- a/ParseSwift.xcodeproj/project.pbxproj +++ b/ParseSwift.xcodeproj/project.pbxproj @@ -151,6 +151,8 @@ F9D7986124D7A93700BEE62E /* NoBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985824D7A93000BEE62E /* NoBody.swift */; }; F9D7986424D7A95800BEE62E /* ParseStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7986224D7A95700BEE62E /* ParseStorage.swift */; }; F9D7986524D7A95800BEE62E /* PrimitiveObjectStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7986324D7A95800BEE62E /* PrimitiveObjectStore.swift */; }; + F9FCA9A724D8A6AB004EBF16 /* NewParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9FCA9A624D8A6AB004EBF16 /* NewParseEncoder.swift */; }; + F9FCA9A924D8ADEE004EBF16 /* NewParseEncoderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9FCA9A824D8ADEE004EBF16 /* NewParseEncoderTests.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -237,6 +239,8 @@ F9D7985924D7A93000BEE62E /* BaseParseUser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseParseUser.swift; sourceTree = ""; }; F9D7986224D7A95700BEE62E /* ParseStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseStorage.swift; sourceTree = ""; }; F9D7986324D7A95800BEE62E /* PrimitiveObjectStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrimitiveObjectStore.swift; sourceTree = ""; }; + F9FCA9A624D8A6AB004EBF16 /* NewParseEncoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewParseEncoder.swift; sourceTree = ""; }; + F9FCA9A824D8ADEE004EBF16 /* NewParseEncoderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewParseEncoderTests.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -369,6 +373,7 @@ 7FFF552A2217E729007C3B4E /* AnyCodableTests */, 4AA8076D1F794C1C008CD551 /* Info.plist */, 4AA8076E1F794C1C008CD551 /* KeychainStoreTests.swift */, + F9FCA9A824D8ADEE004EBF16 /* NewParseEncoderTests.swift */, 911DB13524C4FC100027F3C7 /* ParseObjectCommandTests.swift */, 70E5503D24C7A54C00F6D8D2 /* ParseUserCommandTests.swift */, 911DB12D24C4837E0027F3C7 /* APICommandTests.swift */, @@ -460,6 +465,7 @@ 709075C524B9117500B95310 /* AnyDecodable.swift */, 709075C624B9117500B95310 /* AnyEncodable.swift */, F9D7984C24D7A8F100BEE62E /* Extensions.swift */, + F9FCA9A624D8A6AB004EBF16 /* NewParseEncoder.swift */, F9D7984D24D7A8F100BEE62E /* ParseCoding.swift */, 4A2D8C801F48B3A900EE1FCC /* ParseEncoder.swift */, ); @@ -819,6 +825,7 @@ 4A82B7FF1F256A8F0063D731 /* Query.swift in Sources */, 4AF85BD81F78144900665264 /* URLSession+sync.swift in Sources */, 709075CB24B9117500B95310 /* AnyEncodable.swift in Sources */, + F9FCA9A724D8A6AB004EBF16 /* NewParseEncoder.swift in Sources */, 4A82B7F41F254CCE0063D731 /* File.swift in Sources */, F9D7985424D7A91300BEE62E /* Fetchable.swift in Sources */, 4AF85BD31F78011100665264 /* ParseError.swift in Sources */, @@ -852,6 +859,7 @@ 911DB12C24C3F7720027F3C7 /* MockURLResponse.swift in Sources */, 7FFF552E2217E72A007C3B4E /* AnyEncodableTests.swift in Sources */, 7FFF55302217E72A007C3B4E /* AnyDecodableTests.swift in Sources */, + F9FCA9A924D8ADEE004EBF16 /* NewParseEncoderTests.swift in Sources */, 7FFF552F2217E72A007C3B4E /* AnyCodableTests.swift in Sources */, 4AA807701F794C31008CD551 /* KeychainStoreTests.swift in Sources */, 70E5503E24C7A54C00F6D8D2 /* ParseUserCommandTests.swift in Sources */, diff --git a/Sources/ParseSwift/Coding/NewParseEncoder.swift b/Sources/ParseSwift/Coding/NewParseEncoder.swift new file mode 100644 index 000000000..dca3f4d06 --- /dev/null +++ b/Sources/ParseSwift/Coding/NewParseEncoder.swift @@ -0,0 +1,161 @@ +// +// NewParseEncoder.swift +// ParseSwift +// +// Created by Pranjal Satija on 7/20/20. +// Copyright © 2020 Parse. All rights reserved. +// + +// This rule doesn't allow types with underscores in their names. +// swiftlint:disable type_name + +import Foundation + +public struct NewParseEncoder { + func encode(_ value: T) throws -> [AnyHashable: Any] { + let encoder = _NewParseEncoder(codingPath: [], dictionary: NSMutableDictionary()) + try value.encode(to: encoder) + + // swiftlint:disable:next force_cast + return encoder.dictionary as! [AnyHashable: Any] + } +} + +internal struct _NewParseEncoder: Encoder { + let codingPath: [CodingKey] + let dictionary: NSMutableDictionary + let userInfo: [CodingUserInfoKey: Any] = [:] + + func container(keyedBy type: Key.Type) -> KeyedEncodingContainer where Key: CodingKey { + let container = _NewParseEncoderKeyedEncodingContainer(codingPath: codingPath, dictionary: dictionary) + return KeyedEncodingContainer(container) + } + + func singleValueContainer() -> SingleValueEncodingContainer { + _NewParseEncoderSingleValueEncodingContainer(codingPath: codingPath, dictionary: dictionary) + } + + func unkeyedContainer() -> UnkeyedEncodingContainer { + _NewParseEncoderUnkeyedEncodingContainer(codingPath: codingPath, dictionary: dictionary) + } +} + +internal struct _NewParseEncoderKeyedEncodingContainer: KeyedEncodingContainerProtocol { + let codingPath: [CodingKey] + let dictionary: NSMutableDictionary + + mutating func encodeNil(forKey key: Key) throws { + dictionary[key.stringValue] = nil + } + + mutating func encode(_ value: T, forKey key: Key) throws where T: Encodable { + let encoder = _NewParseEncoder(codingPath: codingPath + [key], dictionary: dictionary) + try value.encode(to: encoder) + } + + mutating func nestedContainer( + keyedBy keyType: NestedKey.Type, + forKey key: Key + ) -> KeyedEncodingContainer where NestedKey: CodingKey { + let container = _NewParseEncoderKeyedEncodingContainer( + codingPath: codingPath + [key], + dictionary: dictionary + ) + + return KeyedEncodingContainer(container) + } + + mutating func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer { + _NewParseEncoderUnkeyedEncodingContainer(codingPath: codingPath + [key], dictionary: dictionary) + } + + mutating func superEncoder() -> Encoder { + fatalError() + } + + mutating func superEncoder(forKey key: Key) -> Encoder { + fatalError() + } +} + +internal struct _NewParseEncoderSingleValueEncodingContainer: SingleValueEncodingContainer { + let codingPath: [CodingKey] + let dictionary: NSMutableDictionary + + var key: String { + codingPath.last?.stringValue ?? "_" + } + + mutating func encodeNil() throws { + dictionary.setValue(nil, forKey: key) + } + + mutating func encode(_ value: T) throws where T: Encodable { + dictionary.setValue(value, forKey: key) + } +} + +internal struct _NewParseEncoderUnkeyedEncodingContainer: UnkeyedEncodingContainer { + let codingPath: [CodingKey] + let dictionary: NSMutableDictionary + + var array: NSMutableArray { + get { + // swiftlint:disable:next force_cast + dictionary[key] as! NSMutableArray + } + + set { dictionary[key] = newValue } + } + + var count: Int { + array.count + } + + var key: String { + codingPath.last?.stringValue ?? "_" + } + + init(codingPath: [CodingKey], dictionary: NSMutableDictionary) { + self.codingPath = codingPath + self.dictionary = dictionary + + self.array = NSMutableArray() + } + + mutating func encodeNil() throws { + array.add(NSNull()) + } + + mutating func encode(_ value: T) throws where T: Encodable { + let encoder = _NewParseEncoder(codingPath: [], dictionary: NSMutableDictionary()) + try value.encode(to: encoder) + + array.add(encoder.dictionary) + } + + mutating func nestedContainer( + keyedBy keyType: NestedKey.Type + ) -> KeyedEncodingContainer where NestedKey: CodingKey { + let dictionary = NSMutableDictionary() + array.add(dictionary) + + let container = _NewParseEncoderKeyedEncodingContainer( + codingPath: [], + dictionary: dictionary + ) + + return KeyedEncodingContainer(container) + } + + mutating func nestedUnkeyedContainer() -> UnkeyedEncodingContainer { + let dictionary = NSMutableDictionary() + array.add(dictionary) + + return _NewParseEncoderUnkeyedEncodingContainer(codingPath: [], dictionary: dictionary) + } + + mutating func superEncoder() -> Encoder { + fatalError() + } +} diff --git a/Tests/ParseSwiftTests/NewParseEncoderTests.swift b/Tests/ParseSwiftTests/NewParseEncoderTests.swift new file mode 100644 index 000000000..25e56c81c --- /dev/null +++ b/Tests/ParseSwiftTests/NewParseEncoderTests.swift @@ -0,0 +1,44 @@ +// +// NewParseEncoderTests.swift +// ParseSwiftTests +// +// Created by Pranjal Satija on 8/3/20. +// Copyright © 2020 Parse Community. All rights reserved. +// + +import Foundation +import XCTest + +@testable import ParseSwift + +class NewParseEncoderTests: XCTestCase { + struct Complex: Codable { + let str: String + let int: Int + let arr: [Int] + } + + struct GameScore: ParseObject { + var ACL: ACL? + var createdAt: Date? + var objectId: String? + var updatedAt: Date? + var score: Int? + var complex: Complex + } + + func test_thatItWorks() { + let score = GameScore(ACL: nil, createdAt: nil, objectId: "test", updatedAt: nil, score: 5, complex: Complex( + str: "yeeee", + int: 50, + arr: [1, 2, 3] + )) + + do { + let encoded = try NewParseEncoder().encode(score) + print(encoded) + } catch { + XCTFail(error.localizedDescription) + } + } +} From 9a74666e346d1f05ec4007db73ce511487408d41 Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Mon, 3 Aug 2020 17:56:30 -0500 Subject: [PATCH 14/30] better --- Sources/ParseSwift/Coding/NewParseEncoder.swift | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Sources/ParseSwift/Coding/NewParseEncoder.swift b/Sources/ParseSwift/Coding/NewParseEncoder.swift index dca3f4d06..feea02e5c 100644 --- a/Sources/ParseSwift/Coding/NewParseEncoder.swift +++ b/Sources/ParseSwift/Coding/NewParseEncoder.swift @@ -49,8 +49,7 @@ internal struct _NewParseEncoderKeyedEncodingContainer: KeyedEnc } mutating func encode(_ value: T, forKey key: Key) throws where T: Encodable { - let encoder = _NewParseEncoder(codingPath: codingPath + [key], dictionary: dictionary) - try value.encode(to: encoder) + dictionary[key.stringValue] = value } mutating func nestedContainer( @@ -128,7 +127,7 @@ internal struct _NewParseEncoderUnkeyedEncodingContainer: UnkeyedEncodingContain } mutating func encode(_ value: T) throws where T: Encodable { - let encoder = _NewParseEncoder(codingPath: [], dictionary: NSMutableDictionary()) + let encoder = _NewParseEncoder(codingPath: codingPath, dictionary: NSMutableDictionary()) try value.encode(to: encoder) array.add(encoder.dictionary) @@ -141,7 +140,7 @@ internal struct _NewParseEncoderUnkeyedEncodingContainer: UnkeyedEncodingContain array.add(dictionary) let container = _NewParseEncoderKeyedEncodingContainer( - codingPath: [], + codingPath: codingPath, dictionary: dictionary ) @@ -152,7 +151,7 @@ internal struct _NewParseEncoderUnkeyedEncodingContainer: UnkeyedEncodingContain let dictionary = NSMutableDictionary() array.add(dictionary) - return _NewParseEncoderUnkeyedEncodingContainer(codingPath: [], dictionary: dictionary) + return _NewParseEncoderUnkeyedEncodingContainer(codingPath: codingPath, dictionary: dictionary) } mutating func superEncoder() -> Encoder { From 72684f224a03d65e3fdf5506700357fab405c6ec Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Mon, 3 Aug 2020 18:10:28 -0500 Subject: [PATCH 15/30] more improvements --- .../ParseSwift/Coding/NewParseEncoder.swift | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/Sources/ParseSwift/Coding/NewParseEncoder.swift b/Sources/ParseSwift/Coding/NewParseEncoder.swift index feea02e5c..12607f3f8 100644 --- a/Sources/ParseSwift/Coding/NewParseEncoder.swift +++ b/Sources/ParseSwift/Coding/NewParseEncoder.swift @@ -38,6 +38,20 @@ internal struct _NewParseEncoder: Encoder { func unkeyedContainer() -> UnkeyedEncodingContainer { _NewParseEncoderUnkeyedEncodingContainer(codingPath: codingPath, dictionary: dictionary) } + + static func encode(_ value: T, to dictionary: NSMutableDictionary, for key: String) throws { + switch value { + case is Bool, is Int, is Int8, is Int16, is Int32, is Int64, is UInt, is UInt8, is UInt16, is UInt32, is UInt64, + is Float, is Double, is String: + dictionary[key] = value + default: + let innerDictionary = NSMutableDictionary() + dictionary[key] = innerDictionary + + let encoder = _NewParseEncoder(codingPath: [], dictionary: innerDictionary) + try value.encode(to: encoder) + } + } } internal struct _NewParseEncoderKeyedEncodingContainer: KeyedEncodingContainerProtocol { @@ -49,7 +63,7 @@ internal struct _NewParseEncoderKeyedEncodingContainer: KeyedEnc } mutating func encode(_ value: T, forKey key: Key) throws where T: Encodable { - dictionary[key.stringValue] = value + try _NewParseEncoder.encode(value, to: dictionary, for: key.stringValue) } mutating func nestedContainer( @@ -86,11 +100,11 @@ internal struct _NewParseEncoderSingleValueEncodingContainer: SingleValueEncodin } mutating func encodeNil() throws { - dictionary.setValue(nil, forKey: key) + dictionary[key] = nil } mutating func encode(_ value: T) throws where T: Encodable { - dictionary.setValue(value, forKey: key) + try _NewParseEncoder.encode(value, to: dictionary, for: key) } } @@ -127,10 +141,7 @@ internal struct _NewParseEncoderUnkeyedEncodingContainer: UnkeyedEncodingContain } mutating func encode(_ value: T) throws where T: Encodable { - let encoder = _NewParseEncoder(codingPath: codingPath, dictionary: NSMutableDictionary()) - try value.encode(to: encoder) - - array.add(encoder.dictionary) + try _NewParseEncoder.encode(value, to: dictionary, for: key) } mutating func nestedContainer( From 4cb2019becc15f0296092fddf570ef6b961eb038 Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Mon, 3 Aug 2020 19:19:27 -0500 Subject: [PATCH 16/30] finished for now --- .../ParseSwift/Coding/NewParseEncoder.swift | 19 ++++++++++--------- .../NewParseEncoderTests.swift | 15 ++++++++++++++- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/Sources/ParseSwift/Coding/NewParseEncoder.swift b/Sources/ParseSwift/Coding/NewParseEncoder.swift index 12607f3f8..94bb34cd1 100644 --- a/Sources/ParseSwift/Coding/NewParseEncoder.swift +++ b/Sources/ParseSwift/Coding/NewParseEncoder.swift @@ -39,17 +39,17 @@ internal struct _NewParseEncoder: Encoder { _NewParseEncoderUnkeyedEncodingContainer(codingPath: codingPath, dictionary: dictionary) } - static func encode(_ value: T, to dictionary: NSMutableDictionary, for key: String) throws { + static func encode(_ value: T, with codingPath: [CodingKey]) throws -> Any { switch value { case is Bool, is Int, is Int8, is Int16, is Int32, is Int64, is UInt, is UInt8, is UInt16, is UInt32, is UInt64, is Float, is Double, is String: - dictionary[key] = value + return value default: - let innerDictionary = NSMutableDictionary() - dictionary[key] = innerDictionary - - let encoder = _NewParseEncoder(codingPath: [], dictionary: innerDictionary) + let dictionary = NSMutableDictionary() + let encoder = _NewParseEncoder(codingPath: codingPath, dictionary: dictionary) try value.encode(to: encoder) + + return codingPath.last.map { dictionary[$0.stringValue] ?? dictionary } ?? dictionary } } } @@ -63,7 +63,7 @@ internal struct _NewParseEncoderKeyedEncodingContainer: KeyedEnc } mutating func encode(_ value: T, forKey key: Key) throws where T: Encodable { - try _NewParseEncoder.encode(value, to: dictionary, for: key.stringValue) + dictionary[key.stringValue] = try _NewParseEncoder.encode(value, with: codingPath + [key]) } mutating func nestedContainer( @@ -104,7 +104,7 @@ internal struct _NewParseEncoderSingleValueEncodingContainer: SingleValueEncodin } mutating func encode(_ value: T) throws where T: Encodable { - try _NewParseEncoder.encode(value, to: dictionary, for: key) + dictionary[key] = try _NewParseEncoder.encode(value, with: codingPath) } } @@ -141,7 +141,8 @@ internal struct _NewParseEncoderUnkeyedEncodingContainer: UnkeyedEncodingContain } mutating func encode(_ value: T) throws where T: Encodable { - try _NewParseEncoder.encode(value, to: dictionary, for: key) + let encoded = try _NewParseEncoder.encode(value, with: codingPath) + array.add(encoded) } mutating func nestedContainer( diff --git a/Tests/ParseSwiftTests/NewParseEncoderTests.swift b/Tests/ParseSwiftTests/NewParseEncoderTests.swift index 25e56c81c..30a1ebdbb 100644 --- a/Tests/ParseSwiftTests/NewParseEncoderTests.swift +++ b/Tests/ParseSwiftTests/NewParseEncoderTests.swift @@ -12,10 +12,19 @@ import XCTest @testable import ParseSwift class NewParseEncoderTests: XCTestCase { + struct NestedComplex: Codable { + let str: String + let int: Int + let arr: [Int] + let nestedArr: [[Int]] + } + struct Complex: Codable { let str: String let int: Int let arr: [Int] + let nestedArr: [[Int]] + let nestedComplex: NestedComplex } struct GameScore: ParseObject { @@ -31,7 +40,11 @@ class NewParseEncoderTests: XCTestCase { let score = GameScore(ACL: nil, createdAt: nil, objectId: "test", updatedAt: nil, score: 5, complex: Complex( str: "yeeee", int: 50, - arr: [1, 2, 3] + arr: [1, 2, 3], + nestedArr: [[1], [2], [3]], + nestedComplex: NestedComplex( + str: "yooooo", int: 60, arr: [4, 5, 6], nestedArr: [[4], [5], [6]] + ) )) do { From 38021aeae97a32b0b443bf853c3f5d84fdcc6d16 Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Mon, 3 Aug 2020 19:37:15 -0500 Subject: [PATCH 17/30] add key skipping --- .../ParseSwift/Coding/NewParseEncoder.swift | 92 ++++++++++++++++--- .../NewParseEncoderTests.swift | 2 +- 2 files changed, 79 insertions(+), 15 deletions(-) diff --git a/Sources/ParseSwift/Coding/NewParseEncoder.swift b/Sources/ParseSwift/Coding/NewParseEncoder.swift index 94bb34cd1..9216c0faa 100644 --- a/Sources/ParseSwift/Coding/NewParseEncoder.swift +++ b/Sources/ParseSwift/Coding/NewParseEncoder.swift @@ -12,8 +12,14 @@ import Foundation public struct NewParseEncoder { + let skippedKeys: Set + + init(skippingKeys: Set = []) { + self.skippedKeys = skippingKeys + } + func encode(_ value: T) throws -> [AnyHashable: Any] { - let encoder = _NewParseEncoder(codingPath: [], dictionary: NSMutableDictionary()) + let encoder = _NewParseEncoder(codingPath: [], dictionary: NSMutableDictionary(), skippingKeys: skippedKeys) try value.encode(to: encoder) // swiftlint:disable:next force_cast @@ -24,29 +30,53 @@ public struct NewParseEncoder { internal struct _NewParseEncoder: Encoder { let codingPath: [CodingKey] let dictionary: NSMutableDictionary + let skippedKeys: Set let userInfo: [CodingUserInfoKey: Any] = [:] + init(codingPath: [CodingKey], dictionary: NSMutableDictionary, skippingKeys: Set) { + self.codingPath = codingPath + self.dictionary = dictionary + self.skippedKeys = skippingKeys + } + func container(keyedBy type: Key.Type) -> KeyedEncodingContainer where Key: CodingKey { - let container = _NewParseEncoderKeyedEncodingContainer(codingPath: codingPath, dictionary: dictionary) + let container = _NewParseEncoderKeyedEncodingContainer( + codingPath: codingPath, + dictionary: dictionary, + skippingKeys: skippedKeys + ) + return KeyedEncodingContainer(container) } func singleValueContainer() -> SingleValueEncodingContainer { - _NewParseEncoderSingleValueEncodingContainer(codingPath: codingPath, dictionary: dictionary) + _NewParseEncoderSingleValueEncodingContainer( + codingPath: codingPath, + dictionary: dictionary, + skippingKeys: skippedKeys + ) } func unkeyedContainer() -> UnkeyedEncodingContainer { - _NewParseEncoderUnkeyedEncodingContainer(codingPath: codingPath, dictionary: dictionary) + _NewParseEncoderUnkeyedEncodingContainer( + codingPath: codingPath, + dictionary: dictionary, + skippingKeys: skippedKeys + ) } - static func encode(_ value: T, with codingPath: [CodingKey]) throws -> Any { + static func encode( + _ value: T, + with codingPath: [CodingKey], + skippingKeys skippedKeys: Set + ) throws -> Any { switch value { case is Bool, is Int, is Int8, is Int16, is Int32, is Int64, is UInt, is UInt8, is UInt16, is UInt32, is UInt64, is Float, is Double, is String: return value default: let dictionary = NSMutableDictionary() - let encoder = _NewParseEncoder(codingPath: codingPath, dictionary: dictionary) + let encoder = _NewParseEncoder(codingPath: codingPath, dictionary: dictionary, skippingKeys: skippedKeys) try value.encode(to: encoder) return codingPath.last.map { dictionary[$0.stringValue] ?? dictionary } ?? dictionary @@ -57,13 +87,28 @@ internal struct _NewParseEncoder: Encoder { internal struct _NewParseEncoderKeyedEncodingContainer: KeyedEncodingContainerProtocol { let codingPath: [CodingKey] let dictionary: NSMutableDictionary + let skippedKeys: Set + + init(codingPath: [CodingKey], dictionary: NSMutableDictionary, skippingKeys: Set) { + self.codingPath = codingPath + self.dictionary = dictionary + self.skippedKeys = skippingKeys + } mutating func encodeNil(forKey key: Key) throws { + if skippedKeys.contains(key.stringValue) { return } + dictionary[key.stringValue] = nil } mutating func encode(_ value: T, forKey key: Key) throws where T: Encodable { - dictionary[key.stringValue] = try _NewParseEncoder.encode(value, with: codingPath + [key]) + if skippedKeys.contains(key.stringValue) { return } + + dictionary[key.stringValue] = try _NewParseEncoder.encode( + value, + with: codingPath + [key], + skippingKeys: skippedKeys + ) } mutating func nestedContainer( @@ -72,14 +117,19 @@ internal struct _NewParseEncoderKeyedEncodingContainer: KeyedEnc ) -> KeyedEncodingContainer where NestedKey: CodingKey { let container = _NewParseEncoderKeyedEncodingContainer( codingPath: codingPath + [key], - dictionary: dictionary + dictionary: dictionary, + skippingKeys: skippedKeys ) return KeyedEncodingContainer(container) } mutating func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer { - _NewParseEncoderUnkeyedEncodingContainer(codingPath: codingPath + [key], dictionary: dictionary) + _NewParseEncoderUnkeyedEncodingContainer( + codingPath: codingPath + [key], + dictionary: dictionary, + skippingKeys: skippedKeys + ) } mutating func superEncoder() -> Encoder { @@ -94,6 +144,13 @@ internal struct _NewParseEncoderKeyedEncodingContainer: KeyedEnc internal struct _NewParseEncoderSingleValueEncodingContainer: SingleValueEncodingContainer { let codingPath: [CodingKey] let dictionary: NSMutableDictionary + let skippedKeys: Set + + init(codingPath: [CodingKey], dictionary: NSMutableDictionary, skippingKeys: Set) { + self.codingPath = codingPath + self.dictionary = dictionary + self.skippedKeys = skippingKeys + } var key: String { codingPath.last?.stringValue ?? "_" @@ -104,13 +161,14 @@ internal struct _NewParseEncoderSingleValueEncodingContainer: SingleValueEncodin } mutating func encode(_ value: T) throws where T: Encodable { - dictionary[key] = try _NewParseEncoder.encode(value, with: codingPath) + dictionary[key] = try _NewParseEncoder.encode(value, with: codingPath, skippingKeys: skippedKeys) } } internal struct _NewParseEncoderUnkeyedEncodingContainer: UnkeyedEncodingContainer { let codingPath: [CodingKey] let dictionary: NSMutableDictionary + let skippedKeys: Set var array: NSMutableArray { get { @@ -129,9 +187,10 @@ internal struct _NewParseEncoderUnkeyedEncodingContainer: UnkeyedEncodingContain codingPath.last?.stringValue ?? "_" } - init(codingPath: [CodingKey], dictionary: NSMutableDictionary) { + init(codingPath: [CodingKey], dictionary: NSMutableDictionary, skippingKeys: Set) { self.codingPath = codingPath self.dictionary = dictionary + self.skippedKeys = skippingKeys self.array = NSMutableArray() } @@ -141,7 +200,7 @@ internal struct _NewParseEncoderUnkeyedEncodingContainer: UnkeyedEncodingContain } mutating func encode(_ value: T) throws where T: Encodable { - let encoded = try _NewParseEncoder.encode(value, with: codingPath) + let encoded = try _NewParseEncoder.encode(value, with: codingPath, skippingKeys: skippedKeys) array.add(encoded) } @@ -153,7 +212,8 @@ internal struct _NewParseEncoderUnkeyedEncodingContainer: UnkeyedEncodingContain let container = _NewParseEncoderKeyedEncodingContainer( codingPath: codingPath, - dictionary: dictionary + dictionary: dictionary, + skippingKeys: skippedKeys ) return KeyedEncodingContainer(container) @@ -163,7 +223,11 @@ internal struct _NewParseEncoderUnkeyedEncodingContainer: UnkeyedEncodingContain let dictionary = NSMutableDictionary() array.add(dictionary) - return _NewParseEncoderUnkeyedEncodingContainer(codingPath: codingPath, dictionary: dictionary) + return _NewParseEncoderUnkeyedEncodingContainer( + codingPath: codingPath, + dictionary: dictionary, + skippingKeys: skippedKeys + ) } mutating func superEncoder() -> Encoder { diff --git a/Tests/ParseSwiftTests/NewParseEncoderTests.swift b/Tests/ParseSwiftTests/NewParseEncoderTests.swift index 30a1ebdbb..150bc797c 100644 --- a/Tests/ParseSwiftTests/NewParseEncoderTests.swift +++ b/Tests/ParseSwiftTests/NewParseEncoderTests.swift @@ -48,7 +48,7 @@ class NewParseEncoderTests: XCTestCase { )) do { - let encoded = try NewParseEncoder().encode(score) + let encoded = try NewParseEncoder(skippingKeys: ["objectId", "ACL", "complex"]).encode(score) print(encoded) } catch { XCTFail(error.localizedDescription) From e41acdf94ffe3bbb42b67a6fa8aec23edb37bd2b Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Tue, 4 Aug 2020 09:48:00 -0500 Subject: [PATCH 18/30] remove old ParseEncoder --- ParseSwift.xcodeproj/project.pbxproj | 22 +- .../ParseSwift/Coding/NewParseEncoder.swift | 236 ----- Sources/ParseSwift/Coding/ParseCoding.swift | 13 +- Sources/ParseSwift/Coding/ParseEncoder.swift | 885 ++++-------------- .../NewParseEncoderTests.swift | 57 -- 5 files changed, 164 insertions(+), 1049 deletions(-) delete mode 100644 Sources/ParseSwift/Coding/NewParseEncoder.swift delete mode 100644 Tests/ParseSwiftTests/NewParseEncoderTests.swift diff --git a/ParseSwift.xcodeproj/project.pbxproj b/ParseSwift.xcodeproj/project.pbxproj index 25182ee41..9db50f280 100644 --- a/ParseSwift.xcodeproj/project.pbxproj +++ b/ParseSwift.xcodeproj/project.pbxproj @@ -7,10 +7,8 @@ objects = { /* Begin PBXBuildFile section */ - 4A2D8C811F48B3A900EE1FCC /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2D8C801F48B3A900EE1FCC /* ParseEncoder.swift */; }; 4A2F14961F4A5F2900A7A7EF /* Responses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14951F4A5F2900A7A7EF /* Responses.swift */; }; 4A2F14991F4A5FB500A7A7EF /* Responses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14951F4A5F2900A7A7EF /* Responses.swift */; }; - 4A65114F1F48E3F3005237DF /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2D8C801F48B3A900EE1FCC /* ParseEncoder.swift */; }; 4A6511501F48E400005237DF /* BatchUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC397711F488F9E00DEA9D3 /* BatchUtils.swift */; }; 4A6511511F48E406005237DF /* ACL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC3976F1F48778900DEA9D3 /* ACL.swift */; }; 4A6511521F48E406005237DF /* GeoPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7ED1F254B820063D731 /* GeoPoint.swift */; }; @@ -92,7 +90,6 @@ 912C9BEC24D302B0009947C3 /* AnyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709075C424B9117400B95310 /* AnyCodable.swift */; }; 912C9BED24D302B0009947C3 /* AnyDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709075C524B9117500B95310 /* AnyDecodable.swift */; }; 912C9BEE24D302B0009947C3 /* AnyEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709075C624B9117500B95310 /* AnyEncodable.swift */; }; - 912C9BEF24D302B0009947C3 /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2D8C801F48B3A900EE1FCC /* ParseEncoder.swift */; }; 912C9BF024D302B0009947C3 /* ParseMutationContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A99A4681F2650CA00D72A59 /* ParseMutationContainer.swift */; }; 912C9BF124D302B0009947C3 /* AddOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA5481F26519B00628B17 /* AddOperation.swift */; }; 912C9BF224D302B0009947C3 /* RemoveOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA54A1F2651D900628B17 /* RemoveOperation.swift */; }; @@ -121,7 +118,6 @@ 912C9C0924D302B2009947C3 /* AnyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709075C424B9117400B95310 /* AnyCodable.swift */; }; 912C9C0A24D302B2009947C3 /* AnyDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709075C524B9117500B95310 /* AnyDecodable.swift */; }; 912C9C0B24D302B2009947C3 /* AnyEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709075C624B9117500B95310 /* AnyEncodable.swift */; }; - 912C9C0C24D302B2009947C3 /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2D8C801F48B3A900EE1FCC /* ParseEncoder.swift */; }; 912C9C0D24D302B2009947C3 /* ParseMutationContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A99A4681F2650CA00D72A59 /* ParseMutationContainer.swift */; }; 912C9C0E24D302B2009947C3 /* AddOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA5481F26519B00628B17 /* AddOperation.swift */; }; 912C9C0F24D302B2009947C3 /* RemoveOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA54A1F2651D900628B17 /* RemoveOperation.swift */; }; @@ -151,8 +147,7 @@ F9D7986124D7A93700BEE62E /* NoBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985824D7A93000BEE62E /* NoBody.swift */; }; F9D7986424D7A95800BEE62E /* ParseStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7986224D7A95700BEE62E /* ParseStorage.swift */; }; F9D7986524D7A95800BEE62E /* PrimitiveObjectStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7986324D7A95800BEE62E /* PrimitiveObjectStore.swift */; }; - F9FCA9A724D8A6AB004EBF16 /* NewParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9FCA9A624D8A6AB004EBF16 /* NewParseEncoder.swift */; }; - F9FCA9A924D8ADEE004EBF16 /* NewParseEncoderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9FCA9A824D8ADEE004EBF16 /* NewParseEncoderTests.swift */; }; + F9FCA9A724D8A6AB004EBF16 /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9FCA9A624D8A6AB004EBF16 /* ParseEncoder.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -174,7 +169,6 @@ /* Begin PBXFileReference section */ 4A1120BF1F49FC3300E32D94 /* LinuxMain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinuxMain.swift; sourceTree = ""; }; - 4A2D8C801F48B3A900EE1FCC /* ParseEncoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseEncoder.swift; sourceTree = ""; }; 4A2F14901F4A41B900A7A7EF /* Asynchronous.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Asynchronous.swift; sourceTree = ""; }; 4A2F14951F4A5F2900A7A7EF /* Responses.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Responses.swift; sourceTree = ""; }; 4A82B7ED1F254B820063D731 /* GeoPoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoPoint.swift; sourceTree = ""; }; @@ -239,8 +233,7 @@ F9D7985924D7A93000BEE62E /* BaseParseUser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseParseUser.swift; sourceTree = ""; }; F9D7986224D7A95700BEE62E /* ParseStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseStorage.swift; sourceTree = ""; }; F9D7986324D7A95800BEE62E /* PrimitiveObjectStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrimitiveObjectStore.swift; sourceTree = ""; }; - F9FCA9A624D8A6AB004EBF16 /* NewParseEncoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewParseEncoder.swift; sourceTree = ""; }; - F9FCA9A824D8ADEE004EBF16 /* NewParseEncoderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewParseEncoderTests.swift; sourceTree = ""; }; + F9FCA9A624D8A6AB004EBF16 /* ParseEncoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseEncoder.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -373,7 +366,6 @@ 7FFF552A2217E729007C3B4E /* AnyCodableTests */, 4AA8076D1F794C1C008CD551 /* Info.plist */, 4AA8076E1F794C1C008CD551 /* KeychainStoreTests.swift */, - F9FCA9A824D8ADEE004EBF16 /* NewParseEncoderTests.swift */, 911DB13524C4FC100027F3C7 /* ParseObjectCommandTests.swift */, 70E5503D24C7A54C00F6D8D2 /* ParseUserCommandTests.swift */, 911DB12D24C4837E0027F3C7 /* APICommandTests.swift */, @@ -465,9 +457,8 @@ 709075C524B9117500B95310 /* AnyDecodable.swift */, 709075C624B9117500B95310 /* AnyEncodable.swift */, F9D7984C24D7A8F100BEE62E /* Extensions.swift */, - F9FCA9A624D8A6AB004EBF16 /* NewParseEncoder.swift */, + F9FCA9A624D8A6AB004EBF16 /* ParseEncoder.swift */, F9D7984D24D7A8F100BEE62E /* ParseCoding.swift */, - 4A2D8C801F48B3A900EE1FCC /* ParseEncoder.swift */, ); path = Coding; sourceTree = ""; @@ -820,12 +811,11 @@ 4AEBA54F1F265A0D00628B17 /* ParseUser.swift in Sources */, 4A99A4691F2650CA00D72A59 /* ParseMutationContainer.swift in Sources */, 4AC397701F48778900DEA9D3 /* ACL.swift in Sources */, - 4A2D8C811F48B3A900EE1FCC /* ParseEncoder.swift in Sources */, 4A99A46E1F26512100D72A59 /* IncrementOperation.swift in Sources */, 4A82B7FF1F256A8F0063D731 /* Query.swift in Sources */, 4AF85BD81F78144900665264 /* URLSession+sync.swift in Sources */, 709075CB24B9117500B95310 /* AnyEncodable.swift in Sources */, - F9FCA9A724D8A6AB004EBF16 /* NewParseEncoder.swift in Sources */, + F9FCA9A724D8A6AB004EBF16 /* ParseEncoder.swift in Sources */, 4A82B7F41F254CCE0063D731 /* File.swift in Sources */, F9D7985424D7A91300BEE62E /* Fetchable.swift in Sources */, 4AF85BD31F78011100665264 /* ParseError.swift in Sources */, @@ -859,7 +849,6 @@ 911DB12C24C3F7720027F3C7 /* MockURLResponse.swift in Sources */, 7FFF552E2217E72A007C3B4E /* AnyEncodableTests.swift in Sources */, 7FFF55302217E72A007C3B4E /* AnyDecodableTests.swift in Sources */, - F9FCA9A924D8ADEE004EBF16 /* NewParseEncoderTests.swift in Sources */, 7FFF552F2217E72A007C3B4E /* AnyCodableTests.swift in Sources */, 4AA807701F794C31008CD551 /* KeychainStoreTests.swift in Sources */, 70E5503E24C7A54C00F6D8D2 /* ParseUserCommandTests.swift in Sources */, @@ -880,7 +869,6 @@ 4AFDA72A1F26DAE1002AE4FC /* Parse.swift in Sources */, 4AFDA7351F26DAE1002AE4FC /* Query.swift in Sources */, 4A2F14991F4A5FB500A7A7EF /* Responses.swift in Sources */, - 4A65114F1F48E3F3005237DF /* ParseEncoder.swift in Sources */, 4AFDA72E1F26DAE1002AE4FC /* AddOperation.swift in Sources */, 4AFDA7311F26DAE1002AE4FC /* AddUniqueOperation.swift in Sources */, 4AF85BD91F78145C00665264 /* URLSession+sync.swift in Sources */, @@ -924,7 +912,6 @@ 912C9C1524D302B2009947C3 /* BatchUtils.swift in Sources */, 912C9C0F24D302B2009947C3 /* RemoveOperation.swift in Sources */, 912C9C1424D302B2009947C3 /* API+Commands.swift in Sources */, - 912C9C0C24D302B2009947C3 /* ParseEncoder.swift in Sources */, 912C9C0624D302B2009947C3 /* GeoPoint.swift in Sources */, 912C9C0024D302B2009947C3 /* (null) in Sources */, 912C9C1324D302B2009947C3 /* API.swift in Sources */, @@ -962,7 +949,6 @@ 912C9BF824D302B0009947C3 /* BatchUtils.swift in Sources */, 912C9BF224D302B0009947C3 /* RemoveOperation.swift in Sources */, 912C9BF724D302B0009947C3 /* API+Commands.swift in Sources */, - 912C9BEF24D302B0009947C3 /* ParseEncoder.swift in Sources */, 912C9BE924D302B0009947C3 /* GeoPoint.swift in Sources */, 912C9BE324D302B0009947C3 /* (null) in Sources */, 912C9BF624D302B0009947C3 /* API.swift in Sources */, diff --git a/Sources/ParseSwift/Coding/NewParseEncoder.swift b/Sources/ParseSwift/Coding/NewParseEncoder.swift deleted file mode 100644 index 9216c0faa..000000000 --- a/Sources/ParseSwift/Coding/NewParseEncoder.swift +++ /dev/null @@ -1,236 +0,0 @@ -// -// NewParseEncoder.swift -// ParseSwift -// -// Created by Pranjal Satija on 7/20/20. -// Copyright © 2020 Parse. All rights reserved. -// - -// This rule doesn't allow types with underscores in their names. -// swiftlint:disable type_name - -import Foundation - -public struct NewParseEncoder { - let skippedKeys: Set - - init(skippingKeys: Set = []) { - self.skippedKeys = skippingKeys - } - - func encode(_ value: T) throws -> [AnyHashable: Any] { - let encoder = _NewParseEncoder(codingPath: [], dictionary: NSMutableDictionary(), skippingKeys: skippedKeys) - try value.encode(to: encoder) - - // swiftlint:disable:next force_cast - return encoder.dictionary as! [AnyHashable: Any] - } -} - -internal struct _NewParseEncoder: Encoder { - let codingPath: [CodingKey] - let dictionary: NSMutableDictionary - let skippedKeys: Set - let userInfo: [CodingUserInfoKey: Any] = [:] - - init(codingPath: [CodingKey], dictionary: NSMutableDictionary, skippingKeys: Set) { - self.codingPath = codingPath - self.dictionary = dictionary - self.skippedKeys = skippingKeys - } - - func container(keyedBy type: Key.Type) -> KeyedEncodingContainer where Key: CodingKey { - let container = _NewParseEncoderKeyedEncodingContainer( - codingPath: codingPath, - dictionary: dictionary, - skippingKeys: skippedKeys - ) - - return KeyedEncodingContainer(container) - } - - func singleValueContainer() -> SingleValueEncodingContainer { - _NewParseEncoderSingleValueEncodingContainer( - codingPath: codingPath, - dictionary: dictionary, - skippingKeys: skippedKeys - ) - } - - func unkeyedContainer() -> UnkeyedEncodingContainer { - _NewParseEncoderUnkeyedEncodingContainer( - codingPath: codingPath, - dictionary: dictionary, - skippingKeys: skippedKeys - ) - } - - static func encode( - _ value: T, - with codingPath: [CodingKey], - skippingKeys skippedKeys: Set - ) throws -> Any { - switch value { - case is Bool, is Int, is Int8, is Int16, is Int32, is Int64, is UInt, is UInt8, is UInt16, is UInt32, is UInt64, - is Float, is Double, is String: - return value - default: - let dictionary = NSMutableDictionary() - let encoder = _NewParseEncoder(codingPath: codingPath, dictionary: dictionary, skippingKeys: skippedKeys) - try value.encode(to: encoder) - - return codingPath.last.map { dictionary[$0.stringValue] ?? dictionary } ?? dictionary - } - } -} - -internal struct _NewParseEncoderKeyedEncodingContainer: KeyedEncodingContainerProtocol { - let codingPath: [CodingKey] - let dictionary: NSMutableDictionary - let skippedKeys: Set - - init(codingPath: [CodingKey], dictionary: NSMutableDictionary, skippingKeys: Set) { - self.codingPath = codingPath - self.dictionary = dictionary - self.skippedKeys = skippingKeys - } - - mutating func encodeNil(forKey key: Key) throws { - if skippedKeys.contains(key.stringValue) { return } - - dictionary[key.stringValue] = nil - } - - mutating func encode(_ value: T, forKey key: Key) throws where T: Encodable { - if skippedKeys.contains(key.stringValue) { return } - - dictionary[key.stringValue] = try _NewParseEncoder.encode( - value, - with: codingPath + [key], - skippingKeys: skippedKeys - ) - } - - mutating func nestedContainer( - keyedBy keyType: NestedKey.Type, - forKey key: Key - ) -> KeyedEncodingContainer where NestedKey: CodingKey { - let container = _NewParseEncoderKeyedEncodingContainer( - codingPath: codingPath + [key], - dictionary: dictionary, - skippingKeys: skippedKeys - ) - - return KeyedEncodingContainer(container) - } - - mutating func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer { - _NewParseEncoderUnkeyedEncodingContainer( - codingPath: codingPath + [key], - dictionary: dictionary, - skippingKeys: skippedKeys - ) - } - - mutating func superEncoder() -> Encoder { - fatalError() - } - - mutating func superEncoder(forKey key: Key) -> Encoder { - fatalError() - } -} - -internal struct _NewParseEncoderSingleValueEncodingContainer: SingleValueEncodingContainer { - let codingPath: [CodingKey] - let dictionary: NSMutableDictionary - let skippedKeys: Set - - init(codingPath: [CodingKey], dictionary: NSMutableDictionary, skippingKeys: Set) { - self.codingPath = codingPath - self.dictionary = dictionary - self.skippedKeys = skippingKeys - } - - var key: String { - codingPath.last?.stringValue ?? "_" - } - - mutating func encodeNil() throws { - dictionary[key] = nil - } - - mutating func encode(_ value: T) throws where T: Encodable { - dictionary[key] = try _NewParseEncoder.encode(value, with: codingPath, skippingKeys: skippedKeys) - } -} - -internal struct _NewParseEncoderUnkeyedEncodingContainer: UnkeyedEncodingContainer { - let codingPath: [CodingKey] - let dictionary: NSMutableDictionary - let skippedKeys: Set - - var array: NSMutableArray { - get { - // swiftlint:disable:next force_cast - dictionary[key] as! NSMutableArray - } - - set { dictionary[key] = newValue } - } - - var count: Int { - array.count - } - - var key: String { - codingPath.last?.stringValue ?? "_" - } - - init(codingPath: [CodingKey], dictionary: NSMutableDictionary, skippingKeys: Set) { - self.codingPath = codingPath - self.dictionary = dictionary - self.skippedKeys = skippingKeys - - self.array = NSMutableArray() - } - - mutating func encodeNil() throws { - array.add(NSNull()) - } - - mutating func encode(_ value: T) throws where T: Encodable { - let encoded = try _NewParseEncoder.encode(value, with: codingPath, skippingKeys: skippedKeys) - array.add(encoded) - } - - mutating func nestedContainer( - keyedBy keyType: NestedKey.Type - ) -> KeyedEncodingContainer where NestedKey: CodingKey { - let dictionary = NSMutableDictionary() - array.add(dictionary) - - let container = _NewParseEncoderKeyedEncodingContainer( - codingPath: codingPath, - dictionary: dictionary, - skippingKeys: skippedKeys - ) - - return KeyedEncodingContainer(container) - } - - mutating func nestedUnkeyedContainer() -> UnkeyedEncodingContainer { - let dictionary = NSMutableDictionary() - array.add(dictionary) - - return _NewParseEncoderUnkeyedEncodingContainer( - codingPath: codingPath, - dictionary: dictionary, - skippingKeys: skippedKeys - ) - } - - mutating func superEncoder() -> Encoder { - fatalError() - } -} diff --git a/Sources/ParseSwift/Coding/ParseCoding.swift b/Sources/ParseSwift/Coding/ParseCoding.swift index 1fdba865e..1ab994b63 100644 --- a/Sources/ParseSwift/Coding/ParseCoding.swift +++ b/Sources/ParseSwift/Coding/ParseCoding.swift @@ -28,17 +28,8 @@ extension ParseCoding { } static func parseEncoder(skipKeys: Bool = true) -> ParseEncoder { - let encoder = ParseEncoder() - encoder.dateEncodingStrategy = dateEncodingStrategy - encoder.shouldEncodeKey = { (key, path) -> Bool in - if skipKeys && path.count == 0 // top level - && Self.forbiddenKeys.contains(key) { - return false - } - - return true - } - + let encoder = ParseEncoder(skippingKeys: skipKeys ? forbiddenKeys : []) + encoder.jsonEncoder.dateEncodingStrategy = dateEncodingStrategy return encoder } } diff --git a/Sources/ParseSwift/Coding/ParseEncoder.swift b/Sources/ParseSwift/Coding/ParseEncoder.swift index 6a507aaf7..99306f3df 100644 --- a/Sources/ParseSwift/Coding/ParseEncoder.swift +++ b/Sources/ParseSwift/Coding/ParseEncoder.swift @@ -1,812 +1,243 @@ -//===----------------------------------------------------------------------===// // -// This source file is part of the Swift.org open source project +// ParseEncoder.swift +// ParseSwift // -// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors -// Licensed under Apache License v2.0 with Runtime Library Exception +// Created by Pranjal Satija on 7/20/20. +// Copyright © 2020 Parse. All rights reserved. // -// See https://swift.org/LICENSE.txt for license information -// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors -// -//===----------------------------------------------------------------------===// - -//===----------------------------------------------------------------------===// -// JSON Encoder -//===----------------------------------------------------------------------===// - -/// `JSONEncoder` facilitates the encoding of `Encodable` values into JSON. -/// `ParseEncoder` facilitates the encoding of `ObjectType` values into JSON. -/// All Credit to Apple, this is a simple encoder with capability of skipping keys at runtime. -import Foundation - -// swiftlint:disable colon -// swiftlint:disable force_cast -// swiftlint:disable line_length -// swiftlint:disable return_arrow_whitespace -// swiftlint:disable trailing_semicolon -// swiftlint:disable file_length -// swiftlint:disable private_over_fileprivate +// This rule doesn't allow types with underscores in their names. // swiftlint:disable type_name -// swiftlint:disable identifier_name - -open class ParseEncoder { - public typealias DataEncodingStrategy = JSONEncoder.DataEncodingStrategy - public typealias DateEncodingStrategy = JSONEncoder.DateEncodingStrategy - public typealias OutputFormatting = JSONEncoder.OutputFormatting - public typealias NonConformingFloatEncodingStrategy = JSONEncoder.NonConformingFloatEncodingStrategy - - /// The output format to produce. Defaults to `[]`. - open var outputFormatting: OutputFormatting = [] - - /// The strategy to use in encoding dates. Defaults to `.deferredToDate`. - open var dateEncodingStrategy: DateEncodingStrategy = .deferredToDate - - /// The strategy to use in encoding binary data. Defaults to `.base64`. - open var dataEncodingStrategy: DataEncodingStrategy = .base64 - - /// The strategy to use in encoding non-conforming numbers. Defaults to `.throw`. - open var nonConformingFloatEncodingStrategy: NonConformingFloatEncodingStrategy = .throw - - /// Contextual user-provided information for use during encoding. - open var userInfo: [CodingUserInfoKey : Any] = [:] - /// Whether or not this encoder should encode a specific `CodingKey`. - open var shouldEncodeKey: ((String, [CodingKey?]) -> Bool) = { (_, _) in true } +import Foundation - /// Options set on the top-level encoder to pass down the encoding hierarchy. - internal struct _Options { - let dateEncodingStrategy: DateEncodingStrategy - let dataEncodingStrategy: DataEncodingStrategy - let nonConformingFloatEncodingStrategy: NonConformingFloatEncodingStrategy - let userInfo: [CodingUserInfoKey : Any] - let shouldEncodeKey: ((String, [CodingKey?]) -> Bool) - } +public struct ParseEncoder { + let jsonEncoder: JSONEncoder + let skippedKeys: Set - /// The options set on the top-level encoder. - fileprivate var options: _Options { - return _Options(dateEncodingStrategy: dateEncodingStrategy, - dataEncodingStrategy: dataEncodingStrategy, - nonConformingFloatEncodingStrategy: nonConformingFloatEncodingStrategy, - userInfo: userInfo, - shouldEncodeKey: shouldEncodeKey) + init(jsonEncoder: JSONEncoder = JSONEncoder(), skippingKeys: Set = []) { + self.jsonEncoder = jsonEncoder + self.skippedKeys = skippingKeys } - // MARK: - Constructing a JSON Encoder - - /// Initializes `self` with default strategies. - public init() {} - - // MARK: - Encoding Values - - /// Encodes the given top-level value and returns its JSON representation. - /// - /// - parameter value: The value to encode. - /// - returns: A new `Data` value containing the encoded JSON data. - /// - throws: `EncodingError.invalidValue` if a non-comforming floating-point value is encountered during encoding, and the encoding strategy is `.throw`. - /// - throws: An error if any value throws an error during encoding. - open func encode(_ value: T) throws -> Data { - let encoder = _JSONEncoder(options: self.options) + func encodeToDictionary(_ value: T) throws -> [AnyHashable: Any] { + let encoder = _NewParseEncoder(codingPath: [], dictionary: NSMutableDictionary(), skippingKeys: skippedKeys) try value.encode(to: encoder) - guard encoder.storage.count > 0 else { - throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: [], debugDescription: "Top-level \(T.self) did not encode any values.")) - } - - let topLevel = encoder.storage.popContainer() - if topLevel is NSNull { - throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: [], debugDescription: "Top-level \(T.self) encoded as null JSON fragment.")) - } else if topLevel is NSNumber { - throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: [], debugDescription: "Top-level \(T.self) encoded as number JSON fragment.")) - } else if topLevel is NSString { - throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: [], debugDescription: "Top-level \(T.self) encoded as string JSON fragment.")) - } - - let writingOptions = JSONSerialization.WritingOptions(rawValue: self.outputFormatting.rawValue) - do { - return try JSONSerialization.data(withJSONObject: topLevel, options: writingOptions) - } catch { - throw EncodingError.invalidValue(value, EncodingError.Context(codingPath: [], debugDescription: "Unable to encode the given top-level value to JSON.")) - } + // swiftlint:disable:next force_cast + return encoder.dictionary as! [AnyHashable: Any] } -} - -// MARK: - _JSONEncoder - -internal class _JSONEncoder : Encoder { - // MARK: Properties - - /// The encoder's storage. - fileprivate var storage: _JSONEncodingStorage - - /// Options set on the top-level encoder. - internal let options: ParseEncoder._Options - /// The path to the current point in encoding. - public var codingPath: [CodingKey] - - /// Contextual user-provided information for use during encoding. - public var userInfo: [CodingUserInfoKey : Any] { - return self.options.userInfo + func encode(_ value: T) throws -> Data { + let dictionary = try encodeToDictionary(value) + return try jsonEncoder.encode(AnyCodable(dictionary)) } +} - // MARK: - Initialization +internal struct _NewParseEncoder: Encoder { + let codingPath: [CodingKey] + let dictionary: NSMutableDictionary + let skippedKeys: Set + let userInfo: [CodingUserInfoKey: Any] = [:] - /// Initializes `self` with the given top-level encoder options. - fileprivate init(options: ParseEncoder._Options, codingPath: [CodingKey] = []) { - self.options = options - self.storage = _JSONEncodingStorage() + init(codingPath: [CodingKey], dictionary: NSMutableDictionary, skippingKeys: Set) { self.codingPath = codingPath + self.dictionary = dictionary + self.skippedKeys = skippingKeys } - /// Returns whether a new element can be encoded at this coding path. - /// - /// `true` if an element has not yet been encoded at this coding path; `false` otherwise. - fileprivate var canEncodeNewValue: Bool { - // Every time a new value gets encoded, the key it's encoded for is pushed onto the coding path (even if it's a nil key from an unkeyed container). - // At the same time, every time a container is requested, a new value gets pushed onto the storage stack. - // If there are more values on the storage stack than on the coding path, it means the value is requesting more than one container, which violates the precondition. - // - // This means that anytime something that can request a new container goes onto the stack, we MUST push a key onto the coding path. - // Things which will not request containers do not need to have the coding path extended for them (but it doesn't matter if it is, because they will not reach here). - return self.storage.count == self.codingPath.count - } - - // MARK: - Encoder Methods - public func container(keyedBy: Key.Type) -> KeyedEncodingContainer { - // If an existing keyed container was already requested, return that one. - let topContainer: NSMutableDictionary - if self.canEncodeNewValue { - // We haven't yet pushed a container at this level; do so here. - topContainer = self.storage.pushKeyedContainer() - } else { - guard let container = self.storage.containers.last as? NSMutableDictionary else { - preconditionFailure("Attempt to push new keyed encoding container when already previously encoded at this path.") - } - - topContainer = container - } + func container(keyedBy type: Key.Type) -> KeyedEncodingContainer where Key: CodingKey { + let container = _NewParseEncoderKeyedEncodingContainer( + codingPath: codingPath, + dictionary: dictionary, + skippingKeys: skippedKeys + ) - let container = _JSONKeyedEncodingContainer(referencing: self, codingPath: self.codingPath, wrapping: topContainer) return KeyedEncodingContainer(container) } - public func unkeyedContainer() -> UnkeyedEncodingContainer { - // If an existing unkeyed container was already requested, return that one. - let topContainer: NSMutableArray - if self.canEncodeNewValue { - // We haven't yet pushed a container at this level; do so here. - topContainer = self.storage.pushUnkeyedContainer() - } else { - guard let container = self.storage.containers.last as? NSMutableArray else { - preconditionFailure("Attempt to push new unkeyed encoding container when already previously encoded at this path.") - } - - topContainer = container + func singleValueContainer() -> SingleValueEncodingContainer { + _NewParseEncoderSingleValueEncodingContainer( + codingPath: codingPath, + dictionary: dictionary, + skippingKeys: skippedKeys + ) + } + + func unkeyedContainer() -> UnkeyedEncodingContainer { + _NewParseEncoderUnkeyedEncodingContainer( + codingPath: codingPath, + dictionary: dictionary, + skippingKeys: skippedKeys + ) + } + + static func encode( + _ value: T, + with codingPath: [CodingKey], + skippingKeys skippedKeys: Set + ) throws -> Any { + switch value { + case is Bool, is Int, is Int8, is Int16, is Int32, is Int64, is UInt, is UInt8, is UInt16, is UInt32, is UInt64, + is Float, is Double, is String: + return value + default: + let dictionary = NSMutableDictionary() + let encoder = _NewParseEncoder(codingPath: codingPath, dictionary: dictionary, skippingKeys: skippedKeys) + try value.encode(to: encoder) + + return codingPath.last.map { dictionary[$0.stringValue] ?? dictionary } ?? dictionary } - - return _JSONUnkeyedEncodingContainer(referencing: self, codingPath: self.codingPath, wrapping: topContainer) - } - - public func singleValueContainer() -> SingleValueEncodingContainer { - return self } } -// MARK: - Encoding Storage and Containers - -fileprivate struct _JSONEncodingStorage { - // MARK: Properties - - /// The container stack. - /// Elements may be any one of the JSON types (NSNull, NSNumber, NSString, NSArray, NSDictionary). - private(set) fileprivate var containers: [NSObject] = [] - - // MARK: - Initialization - - /// Initializes `self` with no containers. - fileprivate init() {} - - // MARK: - Modifying the Stack - - fileprivate var count: Int { - return self.containers.count - } +internal struct _NewParseEncoderKeyedEncodingContainer: KeyedEncodingContainerProtocol { + let codingPath: [CodingKey] + let dictionary: NSMutableDictionary + let skippedKeys: Set - fileprivate mutating func pushKeyedContainer() -> NSMutableDictionary { - let dictionary = NSMutableDictionary() - self.containers.append(dictionary) - return dictionary - } - - fileprivate mutating func pushUnkeyedContainer() -> NSMutableArray { - let array = NSMutableArray() - self.containers.append(array) - return array - } - - fileprivate mutating func push(container: NSObject) { - self.containers.append(container) - } - - fileprivate mutating func popContainer() -> NSObject { - precondition(self.containers.count > 0, "Empty container stack.") - return self.containers.popLast()! - } -} - -// MARK: - Encoding Containers - -fileprivate struct _JSONKeyedEncodingContainer : KeyedEncodingContainerProtocol { - typealias Key = K - - // MARK: Properties - - /// A reference to the encoder we're writing to. - private let encoder: _JSONEncoder - - /// A reference to the container we're writing to. - private let container: NSMutableDictionary - - /// The path of coding keys taken to get to this point in encoding. - private(set) public var codingPath: [CodingKey] - - // MARK: - Initialization - - /// Initializes `self` with the given references. - fileprivate init(referencing encoder: _JSONEncoder, codingPath: [CodingKey], wrapping container: NSMutableDictionary) { - self.encoder = encoder + init(codingPath: [CodingKey], dictionary: NSMutableDictionary, skippingKeys: Set) { self.codingPath = codingPath - self.container = container + self.dictionary = dictionary + self.skippedKeys = skippingKeys } - private func shouldEncode(key: Key) -> Bool { - return encoder.options.shouldEncodeKey(key.stringValue, self.codingPath) - } - - private func shouldSkip(_ key: Key) -> Bool { - return !shouldEncode(key: key) - } + mutating func encodeNil(forKey key: Key) throws { + if skippedKeys.contains(key.stringValue) { return } - // MARK: - KeyedEncodingContainerProtocol Methods - - public mutating func encodeNil(forKey key: Key) throws { if shouldSkip(key) { return }; self.container[key.stringValue] = NSNull() } - public mutating func encode(_ value: Bool, forKey key: Key) throws { if shouldSkip(key) { return }; self.container[key.stringValue] = self.encoder.box(value) } - public mutating func encode(_ value: Int, forKey key: Key) throws { if shouldSkip(key) { return }; self.container[key.stringValue] = self.encoder.box(value) } - public mutating func encode(_ value: Int8, forKey key: Key) throws { if shouldSkip(key) { return }; self.container[key.stringValue] = self.encoder.box(value) } - public mutating func encode(_ value: Int16, forKey key: Key) throws { if shouldSkip(key) { return }; self.container[key.stringValue] = self.encoder.box(value) } - public mutating func encode(_ value: Int32, forKey key: Key) throws { if shouldSkip(key) { return }; self.container[key.stringValue] = self.encoder.box(value) } - public mutating func encode(_ value: Int64, forKey key: Key) throws { if shouldSkip(key) { return }; self.container[key.stringValue] = self.encoder.box(value) } - public mutating func encode(_ value: UInt, forKey key: Key) throws { if shouldSkip(key) { return }; self.container[key.stringValue] = self.encoder.box(value) } - public mutating func encode(_ value: UInt8, forKey key: Key) throws { if shouldSkip(key) { return }; self.container[key.stringValue] = self.encoder.box(value) } - public mutating func encode(_ value: UInt16, forKey key: Key) throws { if shouldSkip(key) { return }; self.container[key.stringValue] = self.encoder.box(value) } - public mutating func encode(_ value: UInt32, forKey key: Key) throws { if shouldSkip(key) { return }; self.container[key.stringValue] = self.encoder.box(value) } - public mutating func encode(_ value: UInt64, forKey key: Key) throws { if shouldSkip(key) { return }; self.container[key.stringValue] = self.encoder.box(value) } - public mutating func encode(_ value: String, forKey key: Key) throws { if shouldSkip(key) { return }; self.container[key.stringValue] = self.encoder.box(value) } - - public mutating func encode(_ value: Float, forKey key: Key) throws { - if shouldSkip(key) { return }; - // Since the float may be invalid and throw, the coding path needs to contain this key. - self.encoder.codingPath.append(key) - defer { self.encoder.codingPath.removeLast() } - self.container[key.stringValue] = try self.encoder.box(value) + dictionary[key.stringValue] = nil } - public mutating func encode(_ value: Double, forKey key: Key) throws { - if shouldSkip(key) { return }; - // Since the double may be invalid and throw, the coding path needs to contain this key. - self.encoder.codingPath.append(key) - defer { self.encoder.codingPath.removeLast() } - self.container[key.stringValue] = try self.encoder.box(value) - } + mutating func encode(_ value: T, forKey key: Key) throws where T: Encodable { + if skippedKeys.contains(key.stringValue) { return } - public mutating func encode(_ value: T, forKey key: Key) throws { - if shouldSkip(key) { return }; - self.encoder.codingPath.append(key) - defer { self.encoder.codingPath.removeLast() } - self.container[key.stringValue] = try self.encoder.box(value) + dictionary[key.stringValue] = try _NewParseEncoder.encode( + value, + with: codingPath + [key], + skippingKeys: skippedKeys + ) } - public mutating func nestedContainer(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer { - let dictionary = NSMutableDictionary() - self.container[key.stringValue] = dictionary - - self.codingPath.append(key) - defer { self.codingPath.removeLast() } + mutating func nestedContainer( + keyedBy keyType: NestedKey.Type, + forKey key: Key + ) -> KeyedEncodingContainer where NestedKey: CodingKey { + let container = _NewParseEncoderKeyedEncodingContainer( + codingPath: codingPath + [key], + dictionary: dictionary, + skippingKeys: skippedKeys + ) - let container = _JSONKeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: dictionary) return KeyedEncodingContainer(container) } - public mutating func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer { - let array = NSMutableArray() - self.container[key.stringValue] = array - - self.codingPath.append(key) - defer { self.codingPath.removeLast() } - return _JSONUnkeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: array) + mutating func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer { + _NewParseEncoderUnkeyedEncodingContainer( + codingPath: codingPath + [key], + dictionary: dictionary, + skippingKeys: skippedKeys + ) } - public mutating func superEncoder() -> Encoder { - return _JSONReferencingEncoder(referencing: self.encoder, at: _JSONKey.super, wrapping: self.container) + mutating func superEncoder() -> Encoder { + fatalError() } - public mutating func superEncoder(forKey key: Key) -> Encoder { - return _JSONReferencingEncoder(referencing: self.encoder, at: key, wrapping: self.container) + mutating func superEncoder(forKey key: Key) -> Encoder { + fatalError() } } -fileprivate struct _JSONUnkeyedEncodingContainer : UnkeyedEncodingContainer { - // MARK: Properties - - /// A reference to the encoder we're writing to. - private let encoder: _JSONEncoder - - /// A reference to the container we're writing to. - private let container: NSMutableArray - - /// The path of coding keys taken to get to this point in encoding. - private(set) public var codingPath: [CodingKey] - - /// The number of elements encoded into the container. - public var count: Int { - return self.container.count - } - - // MARK: - Initialization +internal struct _NewParseEncoderSingleValueEncodingContainer: SingleValueEncodingContainer { + let codingPath: [CodingKey] + let dictionary: NSMutableDictionary + let skippedKeys: Set - /// Initializes `self` with the given references. - fileprivate init(referencing encoder: _JSONEncoder, codingPath: [CodingKey], wrapping container: NSMutableArray) { - self.encoder = encoder + init(codingPath: [CodingKey], dictionary: NSMutableDictionary, skippingKeys: Set) { self.codingPath = codingPath - self.container = container - } - - // MARK: - UnkeyedEncodingContainer Methods - - public mutating func encodeNil() throws { self.container.add(NSNull()) } - public mutating func encode(_ value: Bool) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int8) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int16) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int32) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: Int64) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: UInt) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: UInt8) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: UInt16) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: UInt32) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: UInt64) throws { self.container.add(self.encoder.box(value)) } - public mutating func encode(_ value: String) throws { self.container.add(self.encoder.box(value)) } - - public mutating func encode(_ value: Float) throws { - // Since the float may be invalid and throw, the coding path needs to contain this key. - self.encoder.codingPath.append(_JSONKey(index: self.count)) - defer { self.encoder.codingPath.removeLast() } - self.container.add(try self.encoder.box(value)) - } - - public mutating func encode(_ value: Double) throws { - // Since the double may be invalid and throw, the coding path needs to contain this key. - self.encoder.codingPath.append(_JSONKey(index: self.count)) - defer { self.encoder.codingPath.removeLast() } - self.container.add(try self.encoder.box(value)) - } - - public mutating func encode(_ value: T) throws { - self.encoder.codingPath.append(_JSONKey(index: self.count)) - defer { self.encoder.codingPath.removeLast() } - self.container.add(try self.encoder.box(value)) - } - - public mutating func nestedContainer(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer { - self.codingPath.append(_JSONKey(index: self.count)) - defer { self.codingPath.removeLast() } - - let dictionary = NSMutableDictionary() - self.container.add(dictionary) - - let container = _JSONKeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: dictionary) - return KeyedEncodingContainer(container) - } - - public mutating func nestedUnkeyedContainer() -> UnkeyedEncodingContainer { - self.codingPath.append(_JSONKey(index: self.count)) - defer { self.codingPath.removeLast() } - - let array = NSMutableArray() - self.container.add(array) - return _JSONUnkeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: array) - } - - public mutating func superEncoder() -> Encoder { - return _JSONReferencingEncoder(referencing: self.encoder, at: self.container.count, wrapping: self.container) - } -} - -extension _JSONEncoder : SingleValueEncodingContainer { - // MARK: - SingleValueEncodingContainer Methods - - fileprivate func assertCanEncodeNewValue() { - precondition(self.canEncodeNewValue, "Attempt to encode value through single value container when previously value already encoded.") - } - - public func encodeNil() throws { - assertCanEncodeNewValue() - self.storage.push(container: NSNull()) - } - - public func encode(_ value: Bool) throws { - assertCanEncodeNewValue() - self.storage.push(container: box(value)) - } - - public func encode(_ value: Int) throws { - assertCanEncodeNewValue() - self.storage.push(container: box(value)) - } - - public func encode(_ value: Int8) throws { - assertCanEncodeNewValue() - self.storage.push(container: box(value)) - } - - public func encode(_ value: Int16) throws { - assertCanEncodeNewValue() - self.storage.push(container: box(value)) + self.dictionary = dictionary + self.skippedKeys = skippingKeys } - public func encode(_ value: Int32) throws { - assertCanEncodeNewValue() - self.storage.push(container: box(value)) + var key: String { + codingPath.last?.stringValue ?? "_" } - public func encode(_ value: Int64) throws { - assertCanEncodeNewValue() - self.storage.push(container: box(value)) + mutating func encodeNil() throws { + dictionary[key] = nil } - public func encode(_ value: UInt) throws { - assertCanEncodeNewValue() - self.storage.push(container: box(value)) - } - - public func encode(_ value: UInt8) throws { - assertCanEncodeNewValue() - self.storage.push(container: box(value)) - } - - public func encode(_ value: UInt16) throws { - assertCanEncodeNewValue() - self.storage.push(container: box(value)) - } - - public func encode(_ value: UInt32) throws { - assertCanEncodeNewValue() - self.storage.push(container: box(value)) - } - - public func encode(_ value: UInt64) throws { - assertCanEncodeNewValue() - self.storage.push(container: box(value)) - } - - public func encode(_ value: String) throws { - assertCanEncodeNewValue() - self.storage.push(container: box(value)) - } - - public func encode(_ value: Float) throws { - assertCanEncodeNewValue() - try self.storage.push(container: box(value)) - } - - public func encode(_ value: Double) throws { - assertCanEncodeNewValue() - try self.storage.push(container: box(value)) - } - - public func encode(_ value: T) throws { - assertCanEncodeNewValue() - try self.storage.push(container: box(value)) + mutating func encode(_ value: T) throws where T: Encodable { + dictionary[key] = try _NewParseEncoder.encode(value, with: codingPath, skippingKeys: skippedKeys) } } -// MARK: - Concrete Value Representations - -extension _JSONEncoder { - /// Returns the given value boxed in a container appropriate for pushing onto the container stack. - fileprivate func box(_ value: Bool) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: Int) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: Int8) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: Int16) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: Int32) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: Int64) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: UInt) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: UInt8) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: UInt16) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: UInt32) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: UInt64) -> NSObject { return NSNumber(value: value) } - fileprivate func box(_ value: String) -> NSObject { return NSString(string: value) } - - fileprivate func box(_ float: Float) throws -> NSObject { - guard !float.isInfinite && !float.isNaN else { - guard case let .convertToString(positiveInfinity: posInfString, - negativeInfinity: negInfString, - nan: nanString) = self.options.nonConformingFloatEncodingStrategy else { - throw EncodingError._invalidFloatingPointValue(float, at: codingPath) - } - - if float == Float.infinity { - return NSString(string: posInfString) - } else if float == -Float.infinity { - return NSString(string: negInfString) - } else { - return NSString(string: nanString) - } - } +internal struct _NewParseEncoderUnkeyedEncodingContainer: UnkeyedEncodingContainer { + let codingPath: [CodingKey] + let dictionary: NSMutableDictionary + let skippedKeys: Set - return NSNumber(value: float) - } - - fileprivate func box(_ double: Double) throws -> NSObject { - guard !double.isInfinite && !double.isNaN else { - guard case let .convertToString(positiveInfinity: posInfString, - negativeInfinity: negInfString, - nan: nanString) = self.options.nonConformingFloatEncodingStrategy else { - throw EncodingError._invalidFloatingPointValue(double, at: codingPath) - } - - if double == Double.infinity { - return NSString(string: posInfString) - } else if double == -Double.infinity { - return NSString(string: negInfString) - } else { - return NSString(string: nanString) - } + var array: NSMutableArray { + get { + // swiftlint:disable:next force_cast + dictionary[key] as! NSMutableArray } - return NSNumber(value: double) + set { dictionary[key] = newValue } } - fileprivate func box(_ date: Date) throws -> NSObject { - switch self.options.dateEncodingStrategy { - case .deferredToDate: - // Must be called with a surrounding with(pushedKey:) call. - try date.encode(to: self) - return self.storage.popContainer() - - case .secondsSince1970: - return NSNumber(value: date.timeIntervalSince1970) - - case .millisecondsSince1970: - return NSNumber(value: 1000.0 * date.timeIntervalSince1970) - - case .iso8601: - if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) { - return NSString(string: _iso8601Formatter.string(from: date)) - } else { - fatalError("ISO8601DateFormatter is unavailable on this platform.") - } - - case .formatted(let formatter): - return NSString(string: formatter.string(from: date)) - - case .custom(let closure): - let depth = self.storage.count - try closure(date, self) - - guard self.storage.count > depth else { - // The closure didn't encode anything. Return the default keyed container. - return NSDictionary() - } - - // We can pop because the closure encoded something. - return self.storage.popContainer() - - @unknown default: - if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) { - return NSString(string: _iso8601Formatter.string(from: date)) - } else { - fatalError("ISO8601DateFormatter is unavailable on this platform.") - } - } + var count: Int { + array.count } - fileprivate func box(_ data: Data) throws -> NSObject { - switch self.options.dataEncodingStrategy { - case .deferredToData: - // Must be called with a surrounding with(pushedKey:) call. - try data.encode(to: self) - return self.storage.popContainer() - - case .base64: - return NSString(string: data.base64EncodedString()) - - case .custom(let closure): - let depth = self.storage.count - try closure(data, self) - - guard self.storage.count > depth else { - // The closure didn't encode anything. Return the default keyed container. - return NSDictionary() - } - - // We can pop because the closure encoded something. - return self.storage.popContainer() - @unknown default: - return NSString(string: data.base64EncodedString()) - } - } - - fileprivate func box(_ value: T) throws -> NSObject { - if T.self == Date.self { - // Respect Date encoding strategy - return try self.box((value as! Date)) - } else if T.self == Data.self { - // Respect Data encoding strategy - return try self.box((value as! Data)) - } else if T.self == URL.self { - // Encode URLs as single strings. - return self.box((value as! URL).absoluteString) - } else if T.self == Decimal.self { - // JSONSerialization can natively handle NSDecimalNumber. - return (value as! Decimal) as NSDecimalNumber - } - - // The value should request a container from the _JSONEncoder. - let topContainer = self.storage.containers.last - try value.encode(to: self) - - // The top container should be a new container. - guard self.storage.containers.last! !== topContainer else { - // If the value didn't request a container at all, encode the default container instead. - return NSDictionary() - } - - return self.storage.popContainer() - } -} - -// MARK: - _JSONReferencingEncoder - -/// _JSONReferencingEncoder is a special subclass of _JSONEncoder which has its own storage, but references the contents of a different encoder. -/// It's used in superEncoder(), which returns a new encoder for encoding a superclass -- the lifetime of the encoder should not escape the scope it's created in, but it doesn't necessarily know when it's done being used (to write to the original container). -fileprivate class _JSONReferencingEncoder : _JSONEncoder { - // MARK: Reference types. - - /// The type of container we're referencing. - private enum Reference { - /// Referencing a specific index in an array container. - case array(NSMutableArray, Int) - - /// Referencing a specific key in a dictionary container. - case dictionary(NSMutableDictionary, String) - } - - // MARK: - Properties - - /// The encoder we're referencing. - fileprivate let encoder: _JSONEncoder - - /// The container reference itself. - private let reference: Reference - - // MARK: - Initialization - - /// Initializes `self` by referencing the given array container in the given encoder. - fileprivate init(referencing encoder: _JSONEncoder, at index: Int, wrapping array: NSMutableArray) { - self.encoder = encoder - self.reference = .array(array, index) - super.init(options: encoder.options, codingPath: encoder.codingPath) - - self.codingPath.append(_JSONKey(index: index)) + var key: String { + codingPath.last?.stringValue ?? "_" } - /// Initializes `self` by referencing the given dictionary container in the given encoder. - fileprivate init(referencing encoder: _JSONEncoder, at key: CodingKey, wrapping dictionary: NSMutableDictionary) { - self.encoder = encoder - self.reference = .dictionary(dictionary, key.stringValue) - super.init(options: encoder.options, codingPath: encoder.codingPath) + init(codingPath: [CodingKey], dictionary: NSMutableDictionary, skippingKeys: Set) { + self.codingPath = codingPath + self.dictionary = dictionary + self.skippedKeys = skippingKeys - self.codingPath.append(key) + self.array = NSMutableArray() } - // MARK: - Coding Path Operations - - fileprivate override var canEncodeNewValue: Bool { - // With a regular encoder, the storage and coding path grow together. - // A referencing encoder, however, inherits its parents coding path, as well as the key it was created for. - // We have to take this into account. - return self.storage.count == self.codingPath.count - self.encoder.codingPath.count - 1 + mutating func encodeNil() throws { + array.add(NSNull()) } - // MARK: - Deinitialization - - // Finalizes `self` by writing the contents of our storage to the referenced encoder's storage. - deinit { - let value: Any - switch self.storage.count { - case 0: value = NSDictionary() - case 1: value = self.storage.popContainer() - default: fatalError("Referencing encoder deallocated with multiple containers on stack.") - } - - switch self.reference { - case .array(let array, let index): - array.insert(value, at: index) - - case .dictionary(let dictionary, let key): - dictionary[NSString(string: key)] = value - } + mutating func encode(_ value: T) throws where T: Encodable { + let encoded = try _NewParseEncoder.encode(value, with: codingPath, skippingKeys: skippedKeys) + array.add(encoded) } -} - -//===----------------------------------------------------------------------===// -// Shared Key Types -//===----------------------------------------------------------------------===// -fileprivate struct _JSONKey : CodingKey { - public var stringValue: String - public var intValue: Int? + mutating func nestedContainer( + keyedBy keyType: NestedKey.Type + ) -> KeyedEncodingContainer where NestedKey: CodingKey { + let dictionary = NSMutableDictionary() + array.add(dictionary) - public init?(stringValue: String) { - self.stringValue = stringValue - self.intValue = nil - } + let container = _NewParseEncoderKeyedEncodingContainer( + codingPath: codingPath, + dictionary: dictionary, + skippingKeys: skippedKeys + ) - public init?(intValue: Int) { - self.stringValue = "\(intValue)" - self.intValue = intValue - } - - fileprivate init(index: Int) { - self.stringValue = "Index \(index)" - self.intValue = index + return KeyedEncodingContainer(container) } - fileprivate static let `super` = _JSONKey(stringValue: "super")! -} - -//===----------------------------------------------------------------------===// -// Shared ISO8601 Date Formatter -//===----------------------------------------------------------------------===// - -// NOTE: This value is implicitly lazy and _must_ be lazy. We're compiled against the latest SDK (w/ ISO8601DateFormatter), but linked against whichever Foundation the user has. ISO8601DateFormatter might not exist, so we better not hit this code path on an older OS. -@available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) -fileprivate var _iso8601Formatter: ISO8601DateFormatter = { - let formatter = ISO8601DateFormatter() - formatter.formatOptions = .withInternetDateTime - return formatter -}() - -//===----------------------------------------------------------------------===// -// Error Utilities -//===----------------------------------------------------------------------===// - -fileprivate extension EncodingError { - /// Returns a `.invalidValue` error describing the given invalid floating-point value. - /// - /// - /// - parameter value: The value that was invalid to encode. - /// - parameter path: The path of `CodingKey`s taken to encode this value. - /// - returns: An `EncodingError` with the appropriate path and debug description. - static func _invalidFloatingPointValue(_ value: T, at codingPath: [CodingKey]) -> EncodingError { - let valueDescription: String - if value == T.infinity { - valueDescription = "\(T.self).infinity" - } else if value == -T.infinity { - valueDescription = "-\(T.self).infinity" - } else { - valueDescription = "\(T.self).nan" - } + mutating func nestedUnkeyedContainer() -> UnkeyedEncodingContainer { + let dictionary = NSMutableDictionary() + array.add(dictionary) - let debugDescription = "Unable to encode \(valueDescription) directly in JSON. Use JSONEncoder.NonConformingFloatEncodingStrategy.convertToString to specify how the value should be encoded." - return .invalidValue(value, EncodingError.Context(codingPath: codingPath, debugDescription: debugDescription)) + return _NewParseEncoderUnkeyedEncodingContainer( + codingPath: codingPath, + dictionary: dictionary, + skippingKeys: skippedKeys + ) } -} -extension DecodingError { - static func _typeMismatch(at: [CodingKey], expectation: Any.Type, reality: Any) -> DecodingError { - return DecodingError.typeMismatch(expectation, Context(codingPath: at, debugDescription: "\(reality)")) + mutating func superEncoder() -> Encoder { + fatalError() } } diff --git a/Tests/ParseSwiftTests/NewParseEncoderTests.swift b/Tests/ParseSwiftTests/NewParseEncoderTests.swift deleted file mode 100644 index 150bc797c..000000000 --- a/Tests/ParseSwiftTests/NewParseEncoderTests.swift +++ /dev/null @@ -1,57 +0,0 @@ -// -// NewParseEncoderTests.swift -// ParseSwiftTests -// -// Created by Pranjal Satija on 8/3/20. -// Copyright © 2020 Parse Community. All rights reserved. -// - -import Foundation -import XCTest - -@testable import ParseSwift - -class NewParseEncoderTests: XCTestCase { - struct NestedComplex: Codable { - let str: String - let int: Int - let arr: [Int] - let nestedArr: [[Int]] - } - - struct Complex: Codable { - let str: String - let int: Int - let arr: [Int] - let nestedArr: [[Int]] - let nestedComplex: NestedComplex - } - - struct GameScore: ParseObject { - var ACL: ACL? - var createdAt: Date? - var objectId: String? - var updatedAt: Date? - var score: Int? - var complex: Complex - } - - func test_thatItWorks() { - let score = GameScore(ACL: nil, createdAt: nil, objectId: "test", updatedAt: nil, score: 5, complex: Complex( - str: "yeeee", - int: 50, - arr: [1, 2, 3], - nestedArr: [[1], [2], [3]], - nestedComplex: NestedComplex( - str: "yooooo", int: 60, arr: [4, 5, 6], nestedArr: [[4], [5], [6]] - ) - )) - - do { - let encoded = try NewParseEncoder(skippingKeys: ["objectId", "ACL", "complex"]).encode(score) - print(encoded) - } catch { - XCTFail(error.localizedDescription) - } - } -} From e48f242f03e42f4830626a2a7adf1fe70944a1f4 Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Tue, 4 Aug 2020 10:18:19 -0500 Subject: [PATCH 19/30] fix tests --- ParseSwift.xcodeproj/project.pbxproj | 6 +++ Sources/ParseSwift/Coding/AnyCodable.swift | 10 +++++ Sources/ParseSwift/Coding/AnyEncodable.swift | 22 ++++++++-- Sources/ParseSwift/Coding/ParseCoding.swift | 15 ++++--- Sources/ParseSwift/Coding/ParseEncoder.swift | 44 +++++++++++--------- 5 files changed, 69 insertions(+), 28 deletions(-) diff --git a/ParseSwift.xcodeproj/project.pbxproj b/ParseSwift.xcodeproj/project.pbxproj index 9db50f280..7a08d547a 100644 --- a/ParseSwift.xcodeproj/project.pbxproj +++ b/ParseSwift.xcodeproj/project.pbxproj @@ -131,6 +131,9 @@ 912C9C1724D302B2009947C3 /* Responses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14951F4A5F2900A7A7EF /* Responses.swift */; }; 912C9C1824D302B2009947C3 /* SecureStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AA8074A1F7930E9008CD551 /* SecureStorage.swift */; }; 912C9C1924D302B2009947C3 /* KeychainStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AA8074D1F7931B7008CD551 /* KeychainStore.swift */; }; + F9BB236524D9ACAC00634157 /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9FCA9A624D8A6AB004EBF16 /* ParseEncoder.swift */; }; + F9BB236624D9ACAC00634157 /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9FCA9A624D8A6AB004EBF16 /* ParseEncoder.swift */; }; + F9BB236724D9ACAD00634157 /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9FCA9A624D8A6AB004EBF16 /* ParseEncoder.swift */; }; F9D7984E24D7A8F100BEE62E /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7984C24D7A8F100BEE62E /* Extensions.swift */; }; F9D7984F24D7A8F100BEE62E /* ParseCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7984D24D7A8F100BEE62E /* ParseCoding.swift */; }; F9D7985424D7A91300BEE62E /* Fetchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985024D7A91300BEE62E /* Fetchable.swift */; }; @@ -864,6 +867,7 @@ 4AFDA7301F26DAE1002AE4FC /* DeleteOperation.swift in Sources */, 4AFDA7341F26DAE1002AE4FC /* Pointer.swift in Sources */, F9D7985D24D7A93700BEE62E /* BaseParseUser.swift in Sources */, + F9BB236524D9ACAC00634157 /* ParseEncoder.swift in Sources */, 4AA8074C1F7930E9008CD551 /* SecureStorage.swift in Sources */, 4A6511501F48E400005237DF /* BatchUtils.swift in Sources */, 4AFDA72A1F26DAE1002AE4FC /* Parse.swift in Sources */, @@ -920,6 +924,7 @@ 912C9C0524D302B2009947C3 /* File.swift in Sources */, 912C9C0A24D302B2009947C3 /* AnyDecodable.swift in Sources */, 912C9C1224D302B2009947C3 /* IncrementOperation.swift in Sources */, + F9BB236724D9ACAD00634157 /* ParseEncoder.swift in Sources */, 912C9BFD24D302B2009947C3 /* Parse.swift in Sources */, F9D7985C24D7A93700BEE62E /* BaseParseUser.swift in Sources */, 912C9C0D24D302B2009947C3 /* ParseMutationContainer.swift in Sources */, @@ -957,6 +962,7 @@ 912C9BE824D302B0009947C3 /* File.swift in Sources */, 912C9BED24D302B0009947C3 /* AnyDecodable.swift in Sources */, 912C9BF524D302B0009947C3 /* IncrementOperation.swift in Sources */, + F9BB236624D9ACAC00634157 /* ParseEncoder.swift in Sources */, 912C9BE024D302B0009947C3 /* Parse.swift in Sources */, F9D7985E24D7A93700BEE62E /* BaseParseUser.swift in Sources */, 912C9BF024D302B0009947C3 /* ParseMutationContainer.swift in Sources */, diff --git a/Sources/ParseSwift/Coding/AnyCodable.swift b/Sources/ParseSwift/Coding/AnyCodable.swift index e73a93c14..d631cf700 100755 --- a/Sources/ParseSwift/Coding/AnyCodable.swift +++ b/Sources/ParseSwift/Coding/AnyCodable.swift @@ -16,8 +16,18 @@ import Foundation Source: https://github.com/Flight-School/AnyCodable */ public struct AnyCodable: Codable { + public typealias DateEncodingStrategy = (Date, Encoder) throws -> Void + + public let dateEncodingStrategy: DateEncodingStrategy? public let value: Any + public init(_ value: T?) { + self.dateEncodingStrategy = nil + self.value = value ?? () + } + + public init(_ value: T?, dateEncodingStrategy: DateEncodingStrategy?) { + self.dateEncodingStrategy = dateEncodingStrategy self.value = value ?? () } } diff --git a/Sources/ParseSwift/Coding/AnyEncodable.swift b/Sources/ParseSwift/Coding/AnyEncodable.swift index 6c373bab5..cf47555b8 100755 --- a/Sources/ParseSwift/Coding/AnyEncodable.swift +++ b/Sources/ParseSwift/Coding/AnyEncodable.swift @@ -29,14 +29,24 @@ import Foundation Source: https://github.com/Flight-School/AnyCodable */ public struct AnyEncodable: Encodable { + public let dateEncodingStrategy: AnyCodable.DateEncodingStrategy? public let value: Any + + public init(_ value: T?, dateEncodingStrategy: AnyCodable.DateEncodingStrategy?) { + self.dateEncodingStrategy = dateEncodingStrategy + self.value = value ?? () + } + public init(_ value: T?) { + self.dateEncodingStrategy = nil self.value = value ?? () } } @usableFromInline protocol _AnyEncodable { + var dateEncodingStrategy: AnyCodable.DateEncodingStrategy? { get } + var value: Any { get } init(_ value: T?) } @@ -46,7 +56,13 @@ extension AnyEncodable: _AnyEncodable {} // MARK: - Encodable extension _AnyEncodable { - public func encode(to encoder: Encoder) throws { // swiftlint:disable:this cyclomatic_complexity function_body_length line_length + // swiftlint:disable:next cyclomatic_complexity function_body_length + public func encode(to encoder: Encoder) throws { + if let date = self.value as? Date, let strategy = dateEncodingStrategy { + try strategy(date, encoder) + return + } + var container = encoder.singleValueContainer() switch self.value { case is Void: @@ -84,9 +100,9 @@ extension _AnyEncodable { case let url as URL: try container.encode(url) case let array as [Any?]: - try container.encode(array.map { AnyCodable($0) }) + try container.encode(array.map { AnyCodable($0, dateEncodingStrategy: dateEncodingStrategy) }) case let dictionary as [String: Any?]: - try container.encode(dictionary.mapValues { AnyCodable($0) }) + try container.encode(dictionary.mapValues { AnyCodable($0, dateEncodingStrategy: dateEncodingStrategy) }) default: let context = EncodingError.Context(codingPath: container.codingPath, debugDescription: "AnyCodable value cannot be encoded") diff --git a/Sources/ParseSwift/Coding/ParseCoding.swift b/Sources/ParseSwift/Coding/ParseCoding.swift index 1ab994b63..066eba6f0 100644 --- a/Sources/ParseSwift/Coding/ParseCoding.swift +++ b/Sources/ParseSwift/Coding/ParseCoding.swift @@ -17,7 +17,7 @@ extension ParseCoding { static func jsonEncoder() -> JSONEncoder { let encoder = JSONEncoder() - encoder.dateEncodingStrategy = dateEncodingStrategy + encoder.dateEncodingStrategy = jsonDateEncodingStrategy return encoder } @@ -28,9 +28,10 @@ extension ParseCoding { } static func parseEncoder(skipKeys: Bool = true) -> ParseEncoder { - let encoder = ParseEncoder(skippingKeys: skipKeys ? forbiddenKeys : []) - encoder.jsonEncoder.dateEncodingStrategy = dateEncodingStrategy - return encoder + ParseEncoder( + dateEncodingStrategy: parseDateEncodingStrategy, + skippingKeys: skipKeys ? forbiddenKeys : [] + ) } } @@ -48,12 +49,14 @@ extension ParseCoding { return dateFormatter }() - static let dateEncodingStrategy: JSONEncoder.DateEncodingStrategy = .custom({ (date, enc) in + static let jsonDateEncodingStrategy: JSONEncoder.DateEncodingStrategy = .custom(parseDateEncodingStrategy) + + static let parseDateEncodingStrategy: AnyCodable.DateEncodingStrategy = { (date, enc) in var container = enc.container(keyedBy: DateEncodingKeys.self) try container.encode("Date", forKey: .type) let dateString = dateFormatter.string(from: date) try container.encode(dateString, forKey: .iso) - }) + } static let dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .custom({ (dec) -> Date in do { diff --git a/Sources/ParseSwift/Coding/ParseEncoder.swift b/Sources/ParseSwift/Coding/ParseEncoder.swift index 99306f3df..6ed0a74da 100644 --- a/Sources/ParseSwift/Coding/ParseEncoder.swift +++ b/Sources/ParseSwift/Coding/ParseEncoder.swift @@ -12,16 +12,22 @@ import Foundation public struct ParseEncoder { + let dateEncodingStrategy: AnyCodable.DateEncodingStrategy? let jsonEncoder: JSONEncoder let skippedKeys: Set - init(jsonEncoder: JSONEncoder = JSONEncoder(), skippingKeys: Set = []) { + init( + dateEncodingStrategy: AnyCodable.DateEncodingStrategy? = nil, + jsonEncoder: JSONEncoder = JSONEncoder(), + skippingKeys: Set = [] + ) { + self.dateEncodingStrategy = dateEncodingStrategy self.jsonEncoder = jsonEncoder self.skippedKeys = skippingKeys } func encodeToDictionary(_ value: T) throws -> [AnyHashable: Any] { - let encoder = _NewParseEncoder(codingPath: [], dictionary: NSMutableDictionary(), skippingKeys: skippedKeys) + let encoder = _ParseEncoder(codingPath: [], dictionary: NSMutableDictionary(), skippingKeys: skippedKeys) try value.encode(to: encoder) // swiftlint:disable:next force_cast @@ -30,11 +36,11 @@ public struct ParseEncoder { func encode(_ value: T) throws -> Data { let dictionary = try encodeToDictionary(value) - return try jsonEncoder.encode(AnyCodable(dictionary)) + return try jsonEncoder.encode(AnyCodable(dictionary, dateEncodingStrategy: dateEncodingStrategy!)) } } -internal struct _NewParseEncoder: Encoder { +internal struct _ParseEncoder: Encoder { let codingPath: [CodingKey] let dictionary: NSMutableDictionary let skippedKeys: Set @@ -47,7 +53,7 @@ internal struct _NewParseEncoder: Encoder { } func container(keyedBy type: Key.Type) -> KeyedEncodingContainer where Key: CodingKey { - let container = _NewParseEncoderKeyedEncodingContainer( + let container = _ParseEncoderKeyedEncodingContainer( codingPath: codingPath, dictionary: dictionary, skippingKeys: skippedKeys @@ -57,7 +63,7 @@ internal struct _NewParseEncoder: Encoder { } func singleValueContainer() -> SingleValueEncodingContainer { - _NewParseEncoderSingleValueEncodingContainer( + _ParseEncoderSingleValueEncodingContainer( codingPath: codingPath, dictionary: dictionary, skippingKeys: skippedKeys @@ -65,7 +71,7 @@ internal struct _NewParseEncoder: Encoder { } func unkeyedContainer() -> UnkeyedEncodingContainer { - _NewParseEncoderUnkeyedEncodingContainer( + _ParseEncoderUnkeyedEncodingContainer( codingPath: codingPath, dictionary: dictionary, skippingKeys: skippedKeys @@ -79,11 +85,11 @@ internal struct _NewParseEncoder: Encoder { ) throws -> Any { switch value { case is Bool, is Int, is Int8, is Int16, is Int32, is Int64, is UInt, is UInt8, is UInt16, is UInt32, is UInt64, - is Float, is Double, is String: + is Float, is Double, is String, is Date: return value default: let dictionary = NSMutableDictionary() - let encoder = _NewParseEncoder(codingPath: codingPath, dictionary: dictionary, skippingKeys: skippedKeys) + let encoder = _ParseEncoder(codingPath: codingPath, dictionary: dictionary, skippingKeys: skippedKeys) try value.encode(to: encoder) return codingPath.last.map { dictionary[$0.stringValue] ?? dictionary } ?? dictionary @@ -91,7 +97,7 @@ internal struct _NewParseEncoder: Encoder { } } -internal struct _NewParseEncoderKeyedEncodingContainer: KeyedEncodingContainerProtocol { +internal struct _ParseEncoderKeyedEncodingContainer: KeyedEncodingContainerProtocol { let codingPath: [CodingKey] let dictionary: NSMutableDictionary let skippedKeys: Set @@ -111,7 +117,7 @@ internal struct _NewParseEncoderKeyedEncodingContainer: KeyedEnc mutating func encode(_ value: T, forKey key: Key) throws where T: Encodable { if skippedKeys.contains(key.stringValue) { return } - dictionary[key.stringValue] = try _NewParseEncoder.encode( + dictionary[key.stringValue] = try _ParseEncoder.encode( value, with: codingPath + [key], skippingKeys: skippedKeys @@ -122,7 +128,7 @@ internal struct _NewParseEncoderKeyedEncodingContainer: KeyedEnc keyedBy keyType: NestedKey.Type, forKey key: Key ) -> KeyedEncodingContainer where NestedKey: CodingKey { - let container = _NewParseEncoderKeyedEncodingContainer( + let container = _ParseEncoderKeyedEncodingContainer( codingPath: codingPath + [key], dictionary: dictionary, skippingKeys: skippedKeys @@ -132,7 +138,7 @@ internal struct _NewParseEncoderKeyedEncodingContainer: KeyedEnc } mutating func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer { - _NewParseEncoderUnkeyedEncodingContainer( + _ParseEncoderUnkeyedEncodingContainer( codingPath: codingPath + [key], dictionary: dictionary, skippingKeys: skippedKeys @@ -148,7 +154,7 @@ internal struct _NewParseEncoderKeyedEncodingContainer: KeyedEnc } } -internal struct _NewParseEncoderSingleValueEncodingContainer: SingleValueEncodingContainer { +internal struct _ParseEncoderSingleValueEncodingContainer: SingleValueEncodingContainer { let codingPath: [CodingKey] let dictionary: NSMutableDictionary let skippedKeys: Set @@ -168,11 +174,11 @@ internal struct _NewParseEncoderSingleValueEncodingContainer: SingleValueEncodin } mutating func encode(_ value: T) throws where T: Encodable { - dictionary[key] = try _NewParseEncoder.encode(value, with: codingPath, skippingKeys: skippedKeys) + dictionary[key] = try _ParseEncoder.encode(value, with: codingPath, skippingKeys: skippedKeys) } } -internal struct _NewParseEncoderUnkeyedEncodingContainer: UnkeyedEncodingContainer { +internal struct _ParseEncoderUnkeyedEncodingContainer: UnkeyedEncodingContainer { let codingPath: [CodingKey] let dictionary: NSMutableDictionary let skippedKeys: Set @@ -207,7 +213,7 @@ internal struct _NewParseEncoderUnkeyedEncodingContainer: UnkeyedEncodingContain } mutating func encode(_ value: T) throws where T: Encodable { - let encoded = try _NewParseEncoder.encode(value, with: codingPath, skippingKeys: skippedKeys) + let encoded = try _ParseEncoder.encode(value, with: codingPath, skippingKeys: skippedKeys) array.add(encoded) } @@ -217,7 +223,7 @@ internal struct _NewParseEncoderUnkeyedEncodingContainer: UnkeyedEncodingContain let dictionary = NSMutableDictionary() array.add(dictionary) - let container = _NewParseEncoderKeyedEncodingContainer( + let container = _ParseEncoderKeyedEncodingContainer( codingPath: codingPath, dictionary: dictionary, skippingKeys: skippedKeys @@ -230,7 +236,7 @@ internal struct _NewParseEncoderUnkeyedEncodingContainer: UnkeyedEncodingContain let dictionary = NSMutableDictionary() array.add(dictionary) - return _NewParseEncoderUnkeyedEncodingContainer( + return _ParseEncoderUnkeyedEncodingContainer( codingPath: codingPath, dictionary: dictionary, skippingKeys: skippedKeys From 2e2a164fd64d970d63ccaac64cf7e83cd24b82d3 Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Tue, 4 Aug 2020 10:23:31 -0500 Subject: [PATCH 20/30] add MARK comments to ParseEncoder --- Sources/ParseSwift/Coding/ParseEncoder.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Sources/ParseSwift/Coding/ParseEncoder.swift b/Sources/ParseSwift/Coding/ParseEncoder.swift index 6ed0a74da..c5324156d 100644 --- a/Sources/ParseSwift/Coding/ParseEncoder.swift +++ b/Sources/ParseSwift/Coding/ParseEncoder.swift @@ -11,6 +11,7 @@ import Foundation +// MARK: ParseEncoder public struct ParseEncoder { let dateEncodingStrategy: AnyCodable.DateEncodingStrategy? let jsonEncoder: JSONEncoder @@ -40,6 +41,7 @@ public struct ParseEncoder { } } +// MARK: _ParseEncoder internal struct _ParseEncoder: Encoder { let codingPath: [CodingKey] let dictionary: NSMutableDictionary @@ -97,6 +99,7 @@ internal struct _ParseEncoder: Encoder { } } +// MARK: _ParseEncoderKeyedEncodingContainer internal struct _ParseEncoderKeyedEncodingContainer: KeyedEncodingContainerProtocol { let codingPath: [CodingKey] let dictionary: NSMutableDictionary @@ -154,6 +157,7 @@ internal struct _ParseEncoderKeyedEncodingContainer: KeyedEncodi } } +// MARK: _ParseEncoderSingleValueEncodingContainer internal struct _ParseEncoderSingleValueEncodingContainer: SingleValueEncodingContainer { let codingPath: [CodingKey] let dictionary: NSMutableDictionary @@ -178,6 +182,7 @@ internal struct _ParseEncoderSingleValueEncodingContainer: SingleValueEncodingCo } } +// MARK: _ParseEncoderUnkeyedEncodingContainer internal struct _ParseEncoderUnkeyedEncodingContainer: UnkeyedEncodingContainer { let codingPath: [CodingKey] let dictionary: NSMutableDictionary From bd09c9e3073c4619723fbaf177b2ec60e1cc7794 Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Tue, 4 Aug 2020 10:23:38 -0500 Subject: [PATCH 21/30] fix target membership --- ParseSwift.xcodeproj/project.pbxproj | 52 ++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/ParseSwift.xcodeproj/project.pbxproj b/ParseSwift.xcodeproj/project.pbxproj index 7a08d547a..2db8bdb0d 100644 --- a/ParseSwift.xcodeproj/project.pbxproj +++ b/ParseSwift.xcodeproj/project.pbxproj @@ -134,6 +134,32 @@ F9BB236524D9ACAC00634157 /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9FCA9A624D8A6AB004EBF16 /* ParseEncoder.swift */; }; F9BB236624D9ACAC00634157 /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9FCA9A624D8A6AB004EBF16 /* ParseEncoder.swift */; }; F9BB236724D9ACAD00634157 /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9FCA9A624D8A6AB004EBF16 /* ParseEncoder.swift */; }; + F9BB236824D9B4C100634157 /* Asynchronous.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14901F4A41B900A7A7EF /* Asynchronous.swift */; }; + F9BB236924D9B4C100634157 /* Asynchronous.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14901F4A41B900A7A7EF /* Asynchronous.swift */; }; + F9BB236A24D9B4C600634157 /* Fetchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985024D7A91300BEE62E /* Fetchable.swift */; }; + F9BB236B24D9B4C600634157 /* ParseObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985324D7A91300BEE62E /* ParseObject.swift */; }; + F9BB236C24D9B4C600634157 /* Queryable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985124D7A91300BEE62E /* Queryable.swift */; }; + F9BB236D24D9B4C600634157 /* Saveable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985224D7A91300BEE62E /* Saveable.swift */; }; + F9BB236E24D9B4C600634157 /* Fetchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985024D7A91300BEE62E /* Fetchable.swift */; }; + F9BB236F24D9B4C600634157 /* ParseObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985324D7A91300BEE62E /* ParseObject.swift */; }; + F9BB237024D9B4C600634157 /* Queryable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985124D7A91300BEE62E /* Queryable.swift */; }; + F9BB237124D9B4C600634157 /* Saveable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985224D7A91300BEE62E /* Saveable.swift */; }; + F9BB237224D9B4C700634157 /* Fetchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985024D7A91300BEE62E /* Fetchable.swift */; }; + F9BB237324D9B4C700634157 /* ParseObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985324D7A91300BEE62E /* ParseObject.swift */; }; + F9BB237424D9B4C700634157 /* Queryable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985124D7A91300BEE62E /* Queryable.swift */; }; + F9BB237524D9B4C700634157 /* Saveable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985224D7A91300BEE62E /* Saveable.swift */; }; + F9BB237624D9B4CE00634157 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7984C24D7A8F100BEE62E /* Extensions.swift */; }; + F9BB237724D9B4CE00634157 /* ParseCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7984D24D7A8F100BEE62E /* ParseCoding.swift */; }; + F9BB237824D9B4CE00634157 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7984C24D7A8F100BEE62E /* Extensions.swift */; }; + F9BB237924D9B4CE00634157 /* ParseCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7984D24D7A8F100BEE62E /* ParseCoding.swift */; }; + F9BB237A24D9B4CF00634157 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7984C24D7A8F100BEE62E /* Extensions.swift */; }; + F9BB237B24D9B4CF00634157 /* ParseCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7984D24D7A8F100BEE62E /* ParseCoding.swift */; }; + F9BB237C24D9B4D800634157 /* ParseStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7986224D7A95700BEE62E /* ParseStorage.swift */; }; + F9BB237D24D9B4D800634157 /* PrimitiveObjectStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7986324D7A95800BEE62E /* PrimitiveObjectStore.swift */; }; + F9BB237E24D9B4D800634157 /* ParseStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7986224D7A95700BEE62E /* ParseStorage.swift */; }; + F9BB237F24D9B4D800634157 /* PrimitiveObjectStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7986324D7A95800BEE62E /* PrimitiveObjectStore.swift */; }; + F9BB238024D9B4D900634157 /* ParseStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7986224D7A95700BEE62E /* ParseStorage.swift */; }; + F9BB238124D9B4D900634157 /* PrimitiveObjectStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7986324D7A95800BEE62E /* PrimitiveObjectStore.swift */; }; F9D7984E24D7A8F100BEE62E /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7984C24D7A8F100BEE62E /* Extensions.swift */; }; F9D7984F24D7A8F100BEE62E /* ParseCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7984D24D7A8F100BEE62E /* ParseCoding.swift */; }; F9D7985424D7A91300BEE62E /* Fetchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D7985024D7A91300BEE62E /* Fetchable.swift */; }; @@ -865,6 +891,7 @@ files = ( 709075C824B9117500B95310 /* AnyCodable.swift in Sources */, 4AFDA7301F26DAE1002AE4FC /* DeleteOperation.swift in Sources */, + F9BB236C24D9B4C600634157 /* Queryable.swift in Sources */, 4AFDA7341F26DAE1002AE4FC /* Pointer.swift in Sources */, F9D7985D24D7A93700BEE62E /* BaseParseUser.swift in Sources */, F9BB236524D9ACAC00634157 /* ParseEncoder.swift in Sources */, @@ -874,22 +901,29 @@ 4AFDA7351F26DAE1002AE4FC /* Query.swift in Sources */, 4A2F14991F4A5FB500A7A7EF /* Responses.swift in Sources */, 4AFDA72E1F26DAE1002AE4FC /* AddOperation.swift in Sources */, + F9BB236D24D9B4C600634157 /* Saveable.swift in Sources */, 4AFDA7311F26DAE1002AE4FC /* AddUniqueOperation.swift in Sources */, 4AF85BD91F78145C00665264 /* URLSession+sync.swift in Sources */, 709075CC24B9117500B95310 /* AnyEncodable.swift in Sources */, 4A6511521F48E406005237DF /* GeoPoint.swift in Sources */, 4AF85BD61F7803C100665264 /* ParseError.swift in Sources */, + F9BB236A24D9B4C600634157 /* Fetchable.swift in Sources */, 4AF85BDB1F781ED100665264 /* Asynchronous.swift in Sources */, 4AA8074F1F7931B7008CD551 /* KeychainStore.swift in Sources */, 4AFDA7331F26DAE1002AE4FC /* File.swift in Sources */, + F9BB236B24D9B4C600634157 /* ParseObject.swift in Sources */, 4A6511531F48E410005237DF /* API.swift in Sources */, 4AFDA7321F26DAE1002AE4FC /* IncrementOperation.swift in Sources */, 4AF85BDE1F783BB400665264 /* API+Commands.swift in Sources */, F9D7986024D7A93700BEE62E /* NoBody.swift in Sources */, + F9BB237C24D9B4D800634157 /* ParseStorage.swift in Sources */, 4AFDA72D1F26DAE1002AE4FC /* ParseMutationContainer.swift in Sources */, 709075CA24B9117500B95310 /* AnyDecodable.swift in Sources */, + F9BB237D24D9B4D800634157 /* PrimitiveObjectStore.swift in Sources */, + F9BB237724D9B4CE00634157 /* ParseCoding.swift in Sources */, 4AFDA72C1F26DAE1002AE4FC /* ParseUser.swift in Sources */, 4A6511511F48E406005237DF /* ACL.swift in Sources */, + F9BB237624D9B4CE00634157 /* Extensions.swift in Sources */, 4AFDA72F1F26DAE1002AE4FC /* RemoveOperation.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -903,8 +937,10 @@ 912C9C1824D302B2009947C3 /* SecureStorage.swift in Sources */, 912C9C0924D302B2009947C3 /* AnyCodable.swift in Sources */, 912C9C0B24D302B2009947C3 /* AnyEncodable.swift in Sources */, + F9BB237B24D9B4CF00634157 /* ParseCoding.swift in Sources */, 912C9C0424D302B2009947C3 /* ParseError.swift in Sources */, 912C9BFE24D302B2009947C3 /* (null) in Sources */, + F9BB238024D9B4D900634157 /* ParseStorage.swift in Sources */, 912C9C1624D302B2009947C3 /* URLSession+sync.swift in Sources */, F9D7985F24D7A93700BEE62E /* NoBody.swift in Sources */, 912C9C0724D302B2009947C3 /* Pointer.swift in Sources */, @@ -912,18 +948,25 @@ 912C9C0124D302B2009947C3 /* (null) in Sources */, 912C9C0824D302B2009947C3 /* Query.swift in Sources */, 912C9C0E24D302B2009947C3 /* AddOperation.swift in Sources */, + F9BB237A24D9B4CF00634157 /* Extensions.swift in Sources */, 912C9C0224D302B2009947C3 /* ParseUser.swift in Sources */, 912C9C1524D302B2009947C3 /* BatchUtils.swift in Sources */, + F9BB237324D9B4C700634157 /* ParseObject.swift in Sources */, 912C9C0F24D302B2009947C3 /* RemoveOperation.swift in Sources */, 912C9C1424D302B2009947C3 /* API+Commands.swift in Sources */, 912C9C0624D302B2009947C3 /* GeoPoint.swift in Sources */, + F9BB237424D9B4C700634157 /* Queryable.swift in Sources */, 912C9C0024D302B2009947C3 /* (null) in Sources */, 912C9C1324D302B2009947C3 /* API.swift in Sources */, 912C9C0324D302B2009947C3 /* ACL.swift in Sources */, 912C9BFF24D302B2009947C3 /* (null) in Sources */, 912C9C0524D302B2009947C3 /* File.swift in Sources */, 912C9C0A24D302B2009947C3 /* AnyDecodable.swift in Sources */, + F9BB236924D9B4C100634157 /* Asynchronous.swift in Sources */, + F9BB237524D9B4C700634157 /* Saveable.swift in Sources */, 912C9C1224D302B2009947C3 /* IncrementOperation.swift in Sources */, + F9BB237224D9B4C700634157 /* Fetchable.swift in Sources */, + F9BB238124D9B4D900634157 /* PrimitiveObjectStore.swift in Sources */, F9BB236724D9ACAD00634157 /* ParseEncoder.swift in Sources */, 912C9BFD24D302B2009947C3 /* Parse.swift in Sources */, F9D7985C24D7A93700BEE62E /* BaseParseUser.swift in Sources */, @@ -941,8 +984,10 @@ 912C9BFB24D302B0009947C3 /* SecureStorage.swift in Sources */, 912C9BEC24D302B0009947C3 /* AnyCodable.swift in Sources */, 912C9BEE24D302B0009947C3 /* AnyEncodable.swift in Sources */, + F9BB237924D9B4CE00634157 /* ParseCoding.swift in Sources */, 912C9BE724D302B0009947C3 /* ParseError.swift in Sources */, 912C9BE124D302B0009947C3 /* (null) in Sources */, + F9BB237E24D9B4D800634157 /* ParseStorage.swift in Sources */, 912C9BF924D302B0009947C3 /* URLSession+sync.swift in Sources */, F9D7986124D7A93700BEE62E /* NoBody.swift in Sources */, 912C9BEA24D302B0009947C3 /* Pointer.swift in Sources */, @@ -950,18 +995,25 @@ 912C9BE424D302B0009947C3 /* (null) in Sources */, 912C9BEB24D302B0009947C3 /* Query.swift in Sources */, 912C9BF124D302B0009947C3 /* AddOperation.swift in Sources */, + F9BB237824D9B4CE00634157 /* Extensions.swift in Sources */, 912C9BE524D302B0009947C3 /* ParseUser.swift in Sources */, 912C9BF824D302B0009947C3 /* BatchUtils.swift in Sources */, + F9BB236F24D9B4C600634157 /* ParseObject.swift in Sources */, 912C9BF224D302B0009947C3 /* RemoveOperation.swift in Sources */, 912C9BF724D302B0009947C3 /* API+Commands.swift in Sources */, 912C9BE924D302B0009947C3 /* GeoPoint.swift in Sources */, + F9BB237024D9B4C600634157 /* Queryable.swift in Sources */, 912C9BE324D302B0009947C3 /* (null) in Sources */, 912C9BF624D302B0009947C3 /* API.swift in Sources */, 912C9BE624D302B0009947C3 /* ACL.swift in Sources */, 912C9BE224D302B0009947C3 /* (null) in Sources */, 912C9BE824D302B0009947C3 /* File.swift in Sources */, 912C9BED24D302B0009947C3 /* AnyDecodable.swift in Sources */, + F9BB236824D9B4C100634157 /* Asynchronous.swift in Sources */, + F9BB237124D9B4C600634157 /* Saveable.swift in Sources */, 912C9BF524D302B0009947C3 /* IncrementOperation.swift in Sources */, + F9BB236E24D9B4C600634157 /* Fetchable.swift in Sources */, + F9BB237F24D9B4D800634157 /* PrimitiveObjectStore.swift in Sources */, F9BB236624D9ACAC00634157 /* ParseEncoder.swift in Sources */, 912C9BE024D302B0009947C3 /* Parse.swift in Sources */, F9D7985E24D7A93700BEE62E /* BaseParseUser.swift in Sources */, From c5fd3a8e0e455f32986e4a6d1ca2e7a6ecbe1b73 Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Tue, 4 Aug 2020 12:20:32 -0500 Subject: [PATCH 22/30] finish merging master --- .../Contents.swift | 2 +- .../Contents.swift | 2 +- .../3- Users.xcplaygroundpage/Contents.swift | 2 +- ParseSwift.xcodeproj/project.pbxproj | 749 ++++++++++-------- Sources/ParseSwift/API/API+Commands.swift | 27 +- Sources/ParseSwift/API/BatchUtils.swift | 6 +- Sources/ParseSwift/API/Responses.swift | 6 +- .../API/URLSession+extensions.swift | 2 +- Sources/ParseSwift/Coding/Extensions.swift | 4 + Sources/ParseSwift/Coding/ParseCoding.swift | 2 +- .../AddOperation.swift | 0 .../AddUniqueOperation.swift | 0 .../DeleteOperation.swift | 0 .../IncrementOperation.swift | 0 .../ParseMutationContainer.swift | 0 .../RemoveOperation.swift | 0 .../Objects Protocols/ObjectType+Batch.swift | 38 - .../Objects Protocols/ObjectType+Query.swift | 23 - .../Objects Protocols/ObjectType.swift | 236 ------ .../Objects Protocols/UserType.swift | 150 ---- Sources/ParseSwift/Objects/ParseObject.swift | 43 +- Sources/ParseSwift/Objects/ParseUser.swift | 26 + .../ParseSwift/Parse Types/FindResult.swift | 12 + Sources/ParseSwift/Parse Types/Query.swift | 10 +- .../ParseObjectBatchTests.swift | 62 +- .../ParseObjectCommandTests.swift | 36 +- Tests/ParseSwiftTests/ParseQueryTests.swift | 28 +- .../ParseUserCommandTests.swift | 40 +- 28 files changed, 599 insertions(+), 907 deletions(-) rename Sources/ParseSwift/{MutationOperations => Mutation Operations}/AddOperation.swift (100%) rename Sources/ParseSwift/{MutationOperations => Mutation Operations}/AddUniqueOperation.swift (100%) rename Sources/ParseSwift/{MutationOperations => Mutation Operations}/DeleteOperation.swift (100%) rename Sources/ParseSwift/{MutationOperations => Mutation Operations}/IncrementOperation.swift (100%) rename Sources/ParseSwift/{MutationOperations => Mutation Operations}/ParseMutationContainer.swift (100%) rename Sources/ParseSwift/{MutationOperations => Mutation Operations}/RemoveOperation.swift (100%) delete mode 100644 Sources/ParseSwift/Objects Protocols/ObjectType+Batch.swift delete mode 100644 Sources/ParseSwift/Objects Protocols/ObjectType+Query.swift delete mode 100644 Sources/ParseSwift/Objects Protocols/ObjectType.swift delete mode 100644 Sources/ParseSwift/Objects Protocols/UserType.swift create mode 100644 Sources/ParseSwift/Parse Types/FindResult.swift diff --git a/ParseSwift.playground/Pages/1- Your first Object.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/1- Your first Object.xcplaygroundpage/Contents.swift index 11f608a5f..b41efb313 100644 --- a/ParseSwift.playground/Pages/1- Your first Object.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/1- Your first Object.xcplaygroundpage/Contents.swift @@ -10,7 +10,7 @@ PlaygroundPage.current.needsIndefiniteExecution = true initializeParse() -struct GameScore: ParseSwift.ObjectType { +struct GameScore: ParseSwift.ParseObject { //: Those are required for Object var objectId: String? var createdAt: Date? diff --git a/ParseSwift.playground/Pages/2- Finding Objects.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/2- Finding Objects.xcplaygroundpage/Contents.swift index 6f609fddd..072ad9b59 100644 --- a/ParseSwift.playground/Pages/2- Finding Objects.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/2- Finding Objects.xcplaygroundpage/Contents.swift @@ -10,7 +10,7 @@ PlaygroundPage.current.needsIndefiniteExecution = true initializeParse() -struct GameScore: ParseSwift.ObjectType { +struct GameScore: ParseSwift.ParseObject { var objectId: String? var createdAt: Date? var updatedAt: Date? diff --git a/ParseSwift.playground/Pages/3- Users.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/3- Users.xcplaygroundpage/Contents.swift index 3ba81a5fd..ae7c082e5 100644 --- a/ParseSwift.playground/Pages/3- Users.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/3- Users.xcplaygroundpage/Contents.swift @@ -7,7 +7,7 @@ PlaygroundPage.current.needsIndefiniteExecution = true import ParseSwift initializeParse() -struct User: ParseSwift.UserType { +struct User: ParseSwift.ParseUser { //: Those are required for Object var objectId: String? var createdAt: Date? diff --git a/ParseSwift.xcodeproj/project.pbxproj b/ParseSwift.xcodeproj/project.pbxproj index d9002c3a9..ef7296014 100644 --- a/ParseSwift.xcodeproj/project.pbxproj +++ b/ParseSwift.xcodeproj/project.pbxproj @@ -7,78 +7,19 @@ objects = { /* Begin PBXBuildFile section */ - 4A2D8C811F48B3A900EE1FCC /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2D8C801F48B3A900EE1FCC /* ParseEncoder.swift */; }; - 4A2F14941F4A5E1E00A7A7EF /* ObjectType+Equatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14931F4A5E1E00A7A7EF /* ObjectType+Equatable.swift */; }; - 4A2F14961F4A5F2900A7A7EF /* Responses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14951F4A5F2900A7A7EF /* Responses.swift */; }; - 4A2F14981F4A5F6900A7A7EF /* ObjectType+Batch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14971F4A5F6900A7A7EF /* ObjectType+Batch.swift */; }; - 4A2F14991F4A5FB500A7A7EF /* Responses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14951F4A5F2900A7A7EF /* Responses.swift */; }; - 4A2F149A1F4A5FBA00A7A7EF /* ObjectType+Equatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14931F4A5E1E00A7A7EF /* ObjectType+Equatable.swift */; }; - 4A2F149B1F4A5FBA00A7A7EF /* ObjectType+Batch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14971F4A5F6900A7A7EF /* ObjectType+Batch.swift */; }; - 4A65114F1F48E3F3005237DF /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2D8C801F48B3A900EE1FCC /* ParseEncoder.swift */; }; - 4A6511501F48E400005237DF /* BatchUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC397711F488F9E00DEA9D3 /* BatchUtils.swift */; }; - 4A6511511F48E406005237DF /* ACL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC3976F1F48778900DEA9D3 /* ACL.swift */; }; - 4A6511521F48E406005237DF /* GeoPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7ED1F254B820063D731 /* GeoPoint.swift */; }; - 4A6511531F48E410005237DF /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC397731F488FF900DEA9D3 /* API.swift */; }; - 4A82B7F41F254CCE0063D731 /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7F01F254B820063D731 /* File.swift */; }; - 4A82B7F51F254CCE0063D731 /* GeoPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7ED1F254B820063D731 /* GeoPoint.swift */; }; 4A82B7F61F254CCE0063D731 /* Parse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EE1F254B820063D731 /* Parse.swift */; }; - 4A82B7F71F254CCE0063D731 /* ObjectType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EC1F254B820063D731 /* ObjectType.swift */; }; - 4A82B7F81F254CCE0063D731 /* Pointer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7F11F254B820063D731 /* Pointer.swift */; }; - 4A82B7FF1F256A8F0063D731 /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7FE1F256A8F0063D731 /* Query.swift */; }; - 4A82B8011F256B330063D731 /* ObjectType+Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B8001F256B330063D731 /* ObjectType+Query.swift */; }; - 4A99A4691F2650CA00D72A59 /* ParseMutationContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A99A4681F2650CA00D72A59 /* ParseMutationContainer.swift */; }; - 4A99A46C1F2650FF00D72A59 /* AddUniqueOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A99A46B1F2650FF00D72A59 /* AddUniqueOperation.swift */; }; - 4A99A46E1F26512100D72A59 /* IncrementOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A99A46D1F26512100D72A59 /* IncrementOperation.swift */; }; - 4AA8074B1F7930E9008CD551 /* SecureStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AA8074A1F7930E9008CD551 /* SecureStorage.swift */; }; - 4AA8074C1F7930E9008CD551 /* SecureStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AA8074A1F7930E9008CD551 /* SecureStorage.swift */; }; - 4AA8074E1F7931B7008CD551 /* KeychainStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AA8074D1F7931B7008CD551 /* KeychainStore.swift */; }; - 4AA8074F1F7931B7008CD551 /* KeychainStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AA8074D1F7931B7008CD551 /* KeychainStore.swift */; }; 4AA8075B1F794242008CD551 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AA8075A1F794242008CD551 /* AppDelegate.swift */; }; 4AA807601F794242008CD551 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4AA8075E1F794242008CD551 /* Main.storyboard */; }; 4AA807621F794242008CD551 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4AA807611F794242008CD551 /* Assets.xcassets */; }; 4AA807651F794242008CD551 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4AA807631F794242008CD551 /* LaunchScreen.storyboard */; }; 4AA807701F794C31008CD551 /* KeychainStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AA8076E1F794C1C008CD551 /* KeychainStoreTests.swift */; }; - 4AA807711F794C33008CD551 /* ParseSwiftTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AA8076F1F794C1C008CD551 /* ParseSwiftTests.swift */; }; 4AB8B4FE1F254AE10070F682 /* ParseSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4AB8B4F41F254AE10070F682 /* ParseSwift.framework */; }; 4AB8B5051F254AE10070F682 /* Parse.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AB8B4F71F254AE10070F682 /* Parse.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 4AC397701F48778900DEA9D3 /* ACL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC3976F1F48778900DEA9D3 /* ACL.swift */; }; - 4AC397721F488F9E00DEA9D3 /* BatchUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC397711F488F9E00DEA9D3 /* BatchUtils.swift */; }; - 4AC397741F488FF900DEA9D3 /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC397731F488FF900DEA9D3 /* API.swift */; }; - 4AEBA5491F26519B00628B17 /* AddOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA5481F26519B00628B17 /* AddOperation.swift */; }; - 4AEBA54B1F2651D900628B17 /* RemoveOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA54A1F2651D900628B17 /* RemoveOperation.swift */; }; - 4AEBA54D1F26523800628B17 /* DeleteOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA54C1F26523800628B17 /* DeleteOperation.swift */; }; - 4AEBA54F1F265A0D00628B17 /* UserType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA54E1F265A0D00628B17 /* UserType.swift */; }; - 4AF85BD31F78011100665264 /* ParseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AF85BD21F78011100665264 /* ParseError.swift */; }; - 4AF85BD61F7803C100665264 /* ParseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AF85BD21F78011100665264 /* ParseError.swift */; }; - 4AF85BDD1F783B9800665264 /* API+Commands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AF85BDC1F783B9800665264 /* API+Commands.swift */; }; - 4AF85BDE1F783BB400665264 /* API+Commands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AF85BDC1F783B9800665264 /* API+Commands.swift */; }; 4AFDA72A1F26DAE1002AE4FC /* Parse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EE1F254B820063D731 /* Parse.swift */; }; - 4AFDA72B1F26DAE1002AE4FC /* ObjectType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EC1F254B820063D731 /* ObjectType.swift */; }; - 4AFDA72C1F26DAE1002AE4FC /* UserType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA54E1F265A0D00628B17 /* UserType.swift */; }; - 4AFDA72D1F26DAE1002AE4FC /* ParseMutationContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A99A4681F2650CA00D72A59 /* ParseMutationContainer.swift */; }; - 4AFDA72E1F26DAE1002AE4FC /* AddOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA5481F26519B00628B17 /* AddOperation.swift */; }; - 4AFDA72F1F26DAE1002AE4FC /* RemoveOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA54A1F2651D900628B17 /* RemoveOperation.swift */; }; - 4AFDA7301F26DAE1002AE4FC /* DeleteOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA54C1F26523800628B17 /* DeleteOperation.swift */; }; - 4AFDA7311F26DAE1002AE4FC /* AddUniqueOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A99A46B1F2650FF00D72A59 /* AddUniqueOperation.swift */; }; - 4AFDA7321F26DAE1002AE4FC /* IncrementOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A99A46D1F26512100D72A59 /* IncrementOperation.swift */; }; - 4AFDA7331F26DAE1002AE4FC /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7F01F254B820063D731 /* File.swift */; }; - 4AFDA7341F26DAE1002AE4FC /* Pointer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7F11F254B820063D731 /* Pointer.swift */; }; - 4AFDA7351F26DAE1002AE4FC /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7FE1F256A8F0063D731 /* Query.swift */; }; - 4AFDA7361F26DAE1002AE4FC /* ObjectType+Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B8001F256B330063D731 /* ObjectType+Query.swift */; }; 4AFDA7391F26DAF8002AE4FC /* Parse.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AB8B4F71F254AE10070F682 /* Parse.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 709075C724B9117500B95310 /* AnyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709075C424B9117400B95310 /* AnyCodable.swift */; }; - 709075C824B9117500B95310 /* AnyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709075C424B9117400B95310 /* AnyCodable.swift */; }; - 709075C924B9117500B95310 /* AnyDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709075C524B9117500B95310 /* AnyDecodable.swift */; }; - 709075CA24B9117500B95310 /* AnyDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709075C524B9117500B95310 /* AnyDecodable.swift */; }; - 709075CB24B9117500B95310 /* AnyEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709075C624B9117500B95310 /* AnyEncodable.swift */; }; - 709075CC24B9117500B95310 /* AnyEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709075C624B9117500B95310 /* AnyEncodable.swift */; }; 70C7DC1E24D20E530050419B /* ParseUserCommandTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C7DC1D24D20E530050419B /* ParseUserCommandTests.swift */; }; 70C7DC2124D20F190050419B /* ParseQueryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C7DC1F24D20F180050419B /* ParseQueryTests.swift */; }; 70C7DC2224D20F190050419B /* ParseObjectBatchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C7DC2024D20F190050419B /* ParseObjectBatchTests.swift */; }; - 70C7DC2324D620300050419B /* URLSession+extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E5504224CA4E5F00F6D8D2 /* URLSession+extensions.swift */; }; - 70C7DC2424D620330050419B /* URLSession+extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E5504224CA4E5F00F6D8D2 /* URLSession+extensions.swift */; }; - 70E5504324CA4E6000F6D8D2 /* URLSession+extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E5504224CA4E5F00F6D8D2 /* URLSession+extensions.swift */; }; - 70E5504424CA4E6000F6D8D2 /* URLSession+extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E5504224CA4E5F00F6D8D2 /* URLSession+extensions.swift */; }; 7FFF552E2217E72A007C3B4E /* AnyEncodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FFF552B2217E729007C3B4E /* AnyEncodableTests.swift */; }; 7FFF552F2217E72A007C3B4E /* AnyCodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FFF552C2217E729007C3B4E /* AnyCodableTests.swift */; }; 7FFF55302217E72A007C3B4E /* AnyDecodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FFF552D2217E729007C3B4E /* AnyDecodableTests.swift */; }; @@ -89,63 +30,153 @@ 912C9BCF24D3005D009947C3 /* ParseSwift_watchOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 912C9BCD24D3005D009947C3 /* ParseSwift_watchOS.h */; settings = {ATTRIBUTES = (Public, ); }; }; 912C9BDC24D3011F009947C3 /* ParseSwift_tvOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 912C9BDA24D3011F009947C3 /* ParseSwift_tvOS.h */; settings = {ATTRIBUTES = (Public, ); }; }; 912C9BE024D302B0009947C3 /* Parse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EE1F254B820063D731 /* Parse.swift */; }; - 912C9BE124D302B0009947C3 /* ObjectType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EC1F254B820063D731 /* ObjectType.swift */; }; - 912C9BE224D302B0009947C3 /* ObjectType+Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B8001F256B330063D731 /* ObjectType+Query.swift */; }; - 912C9BE324D302B0009947C3 /* ObjectType+Equatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14931F4A5E1E00A7A7EF /* ObjectType+Equatable.swift */; }; - 912C9BE424D302B0009947C3 /* ObjectType+Batch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14971F4A5F6900A7A7EF /* ObjectType+Batch.swift */; }; - 912C9BE524D302B0009947C3 /* UserType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA54E1F265A0D00628B17 /* UserType.swift */; }; - 912C9BE624D302B0009947C3 /* ACL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC3976F1F48778900DEA9D3 /* ACL.swift */; }; - 912C9BE724D302B0009947C3 /* ParseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AF85BD21F78011100665264 /* ParseError.swift */; }; - 912C9BE824D302B0009947C3 /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7F01F254B820063D731 /* File.swift */; }; - 912C9BE924D302B0009947C3 /* GeoPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7ED1F254B820063D731 /* GeoPoint.swift */; }; - 912C9BEA24D302B0009947C3 /* Pointer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7F11F254B820063D731 /* Pointer.swift */; }; - 912C9BEB24D302B0009947C3 /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7FE1F256A8F0063D731 /* Query.swift */; }; - 912C9BEC24D302B0009947C3 /* AnyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709075C424B9117400B95310 /* AnyCodable.swift */; }; - 912C9BED24D302B0009947C3 /* AnyDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709075C524B9117500B95310 /* AnyDecodable.swift */; }; - 912C9BEE24D302B0009947C3 /* AnyEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709075C624B9117500B95310 /* AnyEncodable.swift */; }; - 912C9BEF24D302B0009947C3 /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2D8C801F48B3A900EE1FCC /* ParseEncoder.swift */; }; - 912C9BF024D302B0009947C3 /* ParseMutationContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A99A4681F2650CA00D72A59 /* ParseMutationContainer.swift */; }; - 912C9BF124D302B0009947C3 /* AddOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA5481F26519B00628B17 /* AddOperation.swift */; }; - 912C9BF224D302B0009947C3 /* RemoveOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA54A1F2651D900628B17 /* RemoveOperation.swift */; }; - 912C9BF324D302B0009947C3 /* DeleteOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA54C1F26523800628B17 /* DeleteOperation.swift */; }; - 912C9BF424D302B0009947C3 /* AddUniqueOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A99A46B1F2650FF00D72A59 /* AddUniqueOperation.swift */; }; - 912C9BF524D302B0009947C3 /* IncrementOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A99A46D1F26512100D72A59 /* IncrementOperation.swift */; }; - 912C9BF624D302B0009947C3 /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC397731F488FF900DEA9D3 /* API.swift */; }; - 912C9BF724D302B0009947C3 /* API+Commands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AF85BDC1F783B9800665264 /* API+Commands.swift */; }; - 912C9BF824D302B0009947C3 /* BatchUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC397711F488F9E00DEA9D3 /* BatchUtils.swift */; }; 912C9BF924D302B0009947C3 /* (null) in Sources */ = {isa = PBXBuildFile; }; - 912C9BFA24D302B0009947C3 /* Responses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14951F4A5F2900A7A7EF /* Responses.swift */; }; - 912C9BFB24D302B0009947C3 /* SecureStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AA8074A1F7930E9008CD551 /* SecureStorage.swift */; }; - 912C9BFC24D302B0009947C3 /* KeychainStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AA8074D1F7931B7008CD551 /* KeychainStore.swift */; }; 912C9BFD24D302B2009947C3 /* Parse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EE1F254B820063D731 /* Parse.swift */; }; - 912C9BFE24D302B2009947C3 /* ObjectType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EC1F254B820063D731 /* ObjectType.swift */; }; - 912C9BFF24D302B2009947C3 /* ObjectType+Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B8001F256B330063D731 /* ObjectType+Query.swift */; }; - 912C9C0024D302B2009947C3 /* ObjectType+Equatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14931F4A5E1E00A7A7EF /* ObjectType+Equatable.swift */; }; - 912C9C0124D302B2009947C3 /* ObjectType+Batch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14971F4A5F6900A7A7EF /* ObjectType+Batch.swift */; }; - 912C9C0224D302B2009947C3 /* UserType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA54E1F265A0D00628B17 /* UserType.swift */; }; - 912C9C0324D302B2009947C3 /* ACL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC3976F1F48778900DEA9D3 /* ACL.swift */; }; - 912C9C0424D302B2009947C3 /* ParseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AF85BD21F78011100665264 /* ParseError.swift */; }; - 912C9C0524D302B2009947C3 /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7F01F254B820063D731 /* File.swift */; }; - 912C9C0624D302B2009947C3 /* GeoPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7ED1F254B820063D731 /* GeoPoint.swift */; }; - 912C9C0724D302B2009947C3 /* Pointer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7F11F254B820063D731 /* Pointer.swift */; }; - 912C9C0824D302B2009947C3 /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7FE1F256A8F0063D731 /* Query.swift */; }; - 912C9C0924D302B2009947C3 /* AnyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709075C424B9117400B95310 /* AnyCodable.swift */; }; - 912C9C0A24D302B2009947C3 /* AnyDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709075C524B9117500B95310 /* AnyDecodable.swift */; }; - 912C9C0B24D302B2009947C3 /* AnyEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709075C624B9117500B95310 /* AnyEncodable.swift */; }; - 912C9C0C24D302B2009947C3 /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2D8C801F48B3A900EE1FCC /* ParseEncoder.swift */; }; - 912C9C0D24D302B2009947C3 /* ParseMutationContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A99A4681F2650CA00D72A59 /* ParseMutationContainer.swift */; }; - 912C9C0E24D302B2009947C3 /* AddOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA5481F26519B00628B17 /* AddOperation.swift */; }; - 912C9C0F24D302B2009947C3 /* RemoveOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA54A1F2651D900628B17 /* RemoveOperation.swift */; }; - 912C9C1024D302B2009947C3 /* DeleteOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AEBA54C1F26523800628B17 /* DeleteOperation.swift */; }; - 912C9C1124D302B2009947C3 /* AddUniqueOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A99A46B1F2650FF00D72A59 /* AddUniqueOperation.swift */; }; - 912C9C1224D302B2009947C3 /* IncrementOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A99A46D1F26512100D72A59 /* IncrementOperation.swift */; }; - 912C9C1324D302B2009947C3 /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC397731F488FF900DEA9D3 /* API.swift */; }; - 912C9C1424D302B2009947C3 /* API+Commands.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AF85BDC1F783B9800665264 /* API+Commands.swift */; }; - 912C9C1524D302B2009947C3 /* BatchUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC397711F488F9E00DEA9D3 /* BatchUtils.swift */; }; 912C9C1624D302B2009947C3 /* (null) in Sources */ = {isa = PBXBuildFile; }; - 912C9C1724D302B2009947C3 /* Responses.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A2F14951F4A5F2900A7A7EF /* Responses.swift */; }; - 912C9C1824D302B2009947C3 /* SecureStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AA8074A1F7930E9008CD551 /* SecureStorage.swift */; }; - 912C9C1924D302B2009947C3 /* KeychainStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AA8074D1F7931B7008CD551 /* KeychainStore.swift */; }; + F97B45CE24D9C6F200F4A88B /* ParseCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B424D9C6F200F4A88B /* ParseCoding.swift */; }; + F97B45CF24D9C6F200F4A88B /* ParseCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B424D9C6F200F4A88B /* ParseCoding.swift */; }; + F97B45D024D9C6F200F4A88B /* ParseCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B424D9C6F200F4A88B /* ParseCoding.swift */; }; + F97B45D124D9C6F200F4A88B /* ParseCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B424D9C6F200F4A88B /* ParseCoding.swift */; }; + F97B45D224D9C6F200F4A88B /* AnyDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B524D9C6F200F4A88B /* AnyDecodable.swift */; }; + F97B45D324D9C6F200F4A88B /* AnyDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B524D9C6F200F4A88B /* AnyDecodable.swift */; }; + F97B45D424D9C6F200F4A88B /* AnyDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B524D9C6F200F4A88B /* AnyDecodable.swift */; }; + F97B45D524D9C6F200F4A88B /* AnyDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B524D9C6F200F4A88B /* AnyDecodable.swift */; }; + F97B45D624D9C6F200F4A88B /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B624D9C6F200F4A88B /* ParseEncoder.swift */; }; + F97B45D724D9C6F200F4A88B /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B624D9C6F200F4A88B /* ParseEncoder.swift */; }; + F97B45D824D9C6F200F4A88B /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B624D9C6F200F4A88B /* ParseEncoder.swift */; }; + F97B45D924D9C6F200F4A88B /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B624D9C6F200F4A88B /* ParseEncoder.swift */; }; + F97B45DA24D9C6F200F4A88B /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B724D9C6F200F4A88B /* Extensions.swift */; }; + F97B45DB24D9C6F200F4A88B /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B724D9C6F200F4A88B /* Extensions.swift */; }; + F97B45DC24D9C6F200F4A88B /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B724D9C6F200F4A88B /* Extensions.swift */; }; + F97B45DD24D9C6F200F4A88B /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B724D9C6F200F4A88B /* Extensions.swift */; }; + F97B45DE24D9C6F200F4A88B /* AnyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B824D9C6F200F4A88B /* AnyCodable.swift */; }; + F97B45DF24D9C6F200F4A88B /* AnyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B824D9C6F200F4A88B /* AnyCodable.swift */; }; + F97B45E024D9C6F200F4A88B /* AnyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B824D9C6F200F4A88B /* AnyCodable.swift */; }; + F97B45E124D9C6F200F4A88B /* AnyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B824D9C6F200F4A88B /* AnyCodable.swift */; }; + F97B45E224D9C6F200F4A88B /* AnyEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B924D9C6F200F4A88B /* AnyEncodable.swift */; }; + F97B45E324D9C6F200F4A88B /* AnyEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B924D9C6F200F4A88B /* AnyEncodable.swift */; }; + F97B45E424D9C6F200F4A88B /* AnyEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B924D9C6F200F4A88B /* AnyEncodable.swift */; }; + F97B45E524D9C6F200F4A88B /* AnyEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B924D9C6F200F4A88B /* AnyEncodable.swift */; }; + F97B45E624D9C6F200F4A88B /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BB24D9C6F200F4A88B /* Query.swift */; }; + F97B45E724D9C6F200F4A88B /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BB24D9C6F200F4A88B /* Query.swift */; }; + F97B45E824D9C6F200F4A88B /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BB24D9C6F200F4A88B /* Query.swift */; }; + F97B45E924D9C6F200F4A88B /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BB24D9C6F200F4A88B /* Query.swift */; }; + F97B45EA24D9C6F200F4A88B /* GeoPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BC24D9C6F200F4A88B /* GeoPoint.swift */; }; + F97B45EB24D9C6F200F4A88B /* GeoPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BC24D9C6F200F4A88B /* GeoPoint.swift */; }; + F97B45EC24D9C6F200F4A88B /* GeoPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BC24D9C6F200F4A88B /* GeoPoint.swift */; }; + F97B45ED24D9C6F200F4A88B /* GeoPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BC24D9C6F200F4A88B /* GeoPoint.swift */; }; + F97B45EE24D9C6F200F4A88B /* BaseParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BD24D9C6F200F4A88B /* BaseParseUser.swift */; }; + F97B45EF24D9C6F200F4A88B /* BaseParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BD24D9C6F200F4A88B /* BaseParseUser.swift */; }; + F97B45F024D9C6F200F4A88B /* BaseParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BD24D9C6F200F4A88B /* BaseParseUser.swift */; }; + F97B45F124D9C6F200F4A88B /* BaseParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BD24D9C6F200F4A88B /* BaseParseUser.swift */; }; + F97B45F224D9C6F200F4A88B /* Pointer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BE24D9C6F200F4A88B /* Pointer.swift */; }; + F97B45F324D9C6F200F4A88B /* Pointer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BE24D9C6F200F4A88B /* Pointer.swift */; }; + F97B45F424D9C6F200F4A88B /* Pointer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BE24D9C6F200F4A88B /* Pointer.swift */; }; + F97B45F524D9C6F200F4A88B /* Pointer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BE24D9C6F200F4A88B /* Pointer.swift */; }; + F97B45F624D9C6F200F4A88B /* ParseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BF24D9C6F200F4A88B /* ParseError.swift */; }; + F97B45F724D9C6F200F4A88B /* ParseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BF24D9C6F200F4A88B /* ParseError.swift */; }; + F97B45F824D9C6F200F4A88B /* ParseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BF24D9C6F200F4A88B /* ParseError.swift */; }; + F97B45F924D9C6F200F4A88B /* ParseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BF24D9C6F200F4A88B /* ParseError.swift */; }; + F97B45FA24D9C6F200F4A88B /* ACL.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C024D9C6F200F4A88B /* ACL.swift */; }; + F97B45FB24D9C6F200F4A88B /* ACL.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C024D9C6F200F4A88B /* ACL.swift */; }; + F97B45FC24D9C6F200F4A88B /* ACL.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C024D9C6F200F4A88B /* ACL.swift */; }; + F97B45FD24D9C6F200F4A88B /* ACL.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C024D9C6F200F4A88B /* ACL.swift */; }; + F97B45FE24D9C6F200F4A88B /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C124D9C6F200F4A88B /* File.swift */; }; + F97B45FF24D9C6F200F4A88B /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C124D9C6F200F4A88B /* File.swift */; }; + F97B460024D9C6F200F4A88B /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C124D9C6F200F4A88B /* File.swift */; }; + F97B460124D9C6F200F4A88B /* File.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C124D9C6F200F4A88B /* File.swift */; }; + F97B460224D9C6F200F4A88B /* NoBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C224D9C6F200F4A88B /* NoBody.swift */; }; + F97B460324D9C6F200F4A88B /* NoBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C224D9C6F200F4A88B /* NoBody.swift */; }; + F97B460424D9C6F200F4A88B /* NoBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C224D9C6F200F4A88B /* NoBody.swift */; }; + F97B460524D9C6F200F4A88B /* NoBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C224D9C6F200F4A88B /* NoBody.swift */; }; + F97B460624D9C6F200F4A88B /* ParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C424D9C6F200F4A88B /* ParseUser.swift */; }; + F97B460724D9C6F200F4A88B /* ParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C424D9C6F200F4A88B /* ParseUser.swift */; }; + F97B460824D9C6F200F4A88B /* ParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C424D9C6F200F4A88B /* ParseUser.swift */; }; + F97B460924D9C6F200F4A88B /* ParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C424D9C6F200F4A88B /* ParseUser.swift */; }; + F97B460A24D9C6F200F4A88B /* Fetchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C524D9C6F200F4A88B /* Fetchable.swift */; }; + F97B460B24D9C6F200F4A88B /* Fetchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C524D9C6F200F4A88B /* Fetchable.swift */; }; + F97B460C24D9C6F200F4A88B /* Fetchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C524D9C6F200F4A88B /* Fetchable.swift */; }; + F97B460D24D9C6F200F4A88B /* Fetchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C524D9C6F200F4A88B /* Fetchable.swift */; }; + F97B460E24D9C6F200F4A88B /* ParseObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C624D9C6F200F4A88B /* ParseObject.swift */; }; + F97B460F24D9C6F200F4A88B /* ParseObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C624D9C6F200F4A88B /* ParseObject.swift */; }; + F97B461024D9C6F200F4A88B /* ParseObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C624D9C6F200F4A88B /* ParseObject.swift */; }; + F97B461124D9C6F200F4A88B /* ParseObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C624D9C6F200F4A88B /* ParseObject.swift */; }; + F97B461224D9C6F200F4A88B /* Saveable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C724D9C6F200F4A88B /* Saveable.swift */; }; + F97B461324D9C6F200F4A88B /* Saveable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C724D9C6F200F4A88B /* Saveable.swift */; }; + F97B461424D9C6F200F4A88B /* Saveable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C724D9C6F200F4A88B /* Saveable.swift */; }; + F97B461524D9C6F200F4A88B /* Saveable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C724D9C6F200F4A88B /* Saveable.swift */; }; + F97B461624D9C6F200F4A88B /* Queryable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C824D9C6F200F4A88B /* Queryable.swift */; }; + F97B461724D9C6F200F4A88B /* Queryable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C824D9C6F200F4A88B /* Queryable.swift */; }; + F97B461824D9C6F200F4A88B /* Queryable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C824D9C6F200F4A88B /* Queryable.swift */; }; + F97B461924D9C6F200F4A88B /* Queryable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C824D9C6F200F4A88B /* Queryable.swift */; }; + F97B461A24D9C6F200F4A88B /* URLSession+sync.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45CA24D9C6F200F4A88B /* URLSession+sync.swift */; }; + F97B461B24D9C6F200F4A88B /* URLSession+sync.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45CA24D9C6F200F4A88B /* URLSession+sync.swift */; }; + F97B461C24D9C6F200F4A88B /* URLSession+sync.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45CA24D9C6F200F4A88B /* URLSession+sync.swift */; }; + F97B461D24D9C6F200F4A88B /* URLSession+sync.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45CA24D9C6F200F4A88B /* URLSession+sync.swift */; }; + F97B461E24D9C6F200F4A88B /* ParseStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45CC24D9C6F200F4A88B /* ParseStorage.swift */; }; + F97B461F24D9C6F200F4A88B /* ParseStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45CC24D9C6F200F4A88B /* ParseStorage.swift */; }; + F97B462024D9C6F200F4A88B /* ParseStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45CC24D9C6F200F4A88B /* ParseStorage.swift */; }; + F97B462124D9C6F200F4A88B /* ParseStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45CC24D9C6F200F4A88B /* ParseStorage.swift */; }; + F97B462224D9C6F200F4A88B /* PrimitiveObjectStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45CD24D9C6F200F4A88B /* PrimitiveObjectStore.swift */; }; + F97B462324D9C6F200F4A88B /* PrimitiveObjectStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45CD24D9C6F200F4A88B /* PrimitiveObjectStore.swift */; }; + F97B462424D9C6F200F4A88B /* PrimitiveObjectStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45CD24D9C6F200F4A88B /* PrimitiveObjectStore.swift */; }; + F97B462524D9C6F200F4A88B /* PrimitiveObjectStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45CD24D9C6F200F4A88B /* PrimitiveObjectStore.swift */; }; + F97B462724D9C72700F4A88B /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462624D9C72700F4A88B /* API.swift */; }; + F97B462824D9C72700F4A88B /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462624D9C72700F4A88B /* API.swift */; }; + F97B462924D9C72700F4A88B /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462624D9C72700F4A88B /* API.swift */; }; + F97B462A24D9C72700F4A88B /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462624D9C72700F4A88B /* API.swift */; }; + F97B462F24D9C74400F4A88B /* BatchUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462B24D9C74400F4A88B /* BatchUtils.swift */; }; + F97B463024D9C74400F4A88B /* BatchUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462B24D9C74400F4A88B /* BatchUtils.swift */; }; + F97B463124D9C74400F4A88B /* BatchUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462B24D9C74400F4A88B /* BatchUtils.swift */; }; + F97B463224D9C74400F4A88B /* BatchUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462B24D9C74400F4A88B /* BatchUtils.swift */; }; + F97B463324D9C74400F4A88B /* URLSession+extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462C24D9C74400F4A88B /* URLSession+extensions.swift */; }; + F97B463424D9C74400F4A88B /* URLSession+extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462C24D9C74400F4A88B /* URLSession+extensions.swift */; }; + F97B463524D9C74400F4A88B /* URLSession+extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462C24D9C74400F4A88B /* URLSession+extensions.swift */; }; + F97B463624D9C74400F4A88B /* URLSession+extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462C24D9C74400F4A88B /* URLSession+extensions.swift */; }; + F97B463724D9C74400F4A88B /* Responses.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462D24D9C74400F4A88B /* Responses.swift */; }; + F97B463824D9C74400F4A88B /* Responses.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462D24D9C74400F4A88B /* Responses.swift */; }; + F97B463924D9C74400F4A88B /* Responses.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462D24D9C74400F4A88B /* Responses.swift */; }; + F97B463A24D9C74400F4A88B /* Responses.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462D24D9C74400F4A88B /* Responses.swift */; }; + F97B463B24D9C74400F4A88B /* API+Commands.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462E24D9C74400F4A88B /* API+Commands.swift */; }; + F97B463C24D9C74400F4A88B /* API+Commands.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462E24D9C74400F4A88B /* API+Commands.swift */; }; + F97B463D24D9C74400F4A88B /* API+Commands.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462E24D9C74400F4A88B /* API+Commands.swift */; }; + F97B463E24D9C74400F4A88B /* API+Commands.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462E24D9C74400F4A88B /* API+Commands.swift */; }; + F97B464624D9C78B00F4A88B /* ParseMutationContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464024D9C78B00F4A88B /* ParseMutationContainer.swift */; }; + F97B464724D9C78B00F4A88B /* ParseMutationContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464024D9C78B00F4A88B /* ParseMutationContainer.swift */; }; + F97B464824D9C78B00F4A88B /* ParseMutationContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464024D9C78B00F4A88B /* ParseMutationContainer.swift */; }; + F97B464924D9C78B00F4A88B /* ParseMutationContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464024D9C78B00F4A88B /* ParseMutationContainer.swift */; }; + F97B464A24D9C78B00F4A88B /* DeleteOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464124D9C78B00F4A88B /* DeleteOperation.swift */; }; + F97B464B24D9C78B00F4A88B /* DeleteOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464124D9C78B00F4A88B /* DeleteOperation.swift */; }; + F97B464C24D9C78B00F4A88B /* DeleteOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464124D9C78B00F4A88B /* DeleteOperation.swift */; }; + F97B464D24D9C78B00F4A88B /* DeleteOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464124D9C78B00F4A88B /* DeleteOperation.swift */; }; + F97B464E24D9C78B00F4A88B /* AddOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464224D9C78B00F4A88B /* AddOperation.swift */; }; + F97B464F24D9C78B00F4A88B /* AddOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464224D9C78B00F4A88B /* AddOperation.swift */; }; + F97B465024D9C78B00F4A88B /* AddOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464224D9C78B00F4A88B /* AddOperation.swift */; }; + F97B465124D9C78C00F4A88B /* AddOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464224D9C78B00F4A88B /* AddOperation.swift */; }; + F97B465224D9C78C00F4A88B /* AddUniqueOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464324D9C78B00F4A88B /* AddUniqueOperation.swift */; }; + F97B465324D9C78C00F4A88B /* AddUniqueOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464324D9C78B00F4A88B /* AddUniqueOperation.swift */; }; + F97B465424D9C78C00F4A88B /* AddUniqueOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464324D9C78B00F4A88B /* AddUniqueOperation.swift */; }; + F97B465524D9C78C00F4A88B /* AddUniqueOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464324D9C78B00F4A88B /* AddUniqueOperation.swift */; }; + F97B465624D9C78C00F4A88B /* RemoveOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464424D9C78B00F4A88B /* RemoveOperation.swift */; }; + F97B465724D9C78C00F4A88B /* RemoveOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464424D9C78B00F4A88B /* RemoveOperation.swift */; }; + F97B465824D9C78C00F4A88B /* RemoveOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464424D9C78B00F4A88B /* RemoveOperation.swift */; }; + F97B465924D9C78C00F4A88B /* RemoveOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464424D9C78B00F4A88B /* RemoveOperation.swift */; }; + F97B465A24D9C78C00F4A88B /* IncrementOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464524D9C78B00F4A88B /* IncrementOperation.swift */; }; + F97B465B24D9C78C00F4A88B /* IncrementOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464524D9C78B00F4A88B /* IncrementOperation.swift */; }; + F97B465C24D9C78C00F4A88B /* IncrementOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464524D9C78B00F4A88B /* IncrementOperation.swift */; }; + F97B465D24D9C78C00F4A88B /* IncrementOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464524D9C78B00F4A88B /* IncrementOperation.swift */; }; + F97B465F24D9C7B500F4A88B /* KeychainStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B465E24D9C7B500F4A88B /* KeychainStore.swift */; }; + F97B466024D9C7B500F4A88B /* KeychainStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B465E24D9C7B500F4A88B /* KeychainStore.swift */; }; + F97B466124D9C7B500F4A88B /* KeychainStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B465E24D9C7B500F4A88B /* KeychainStore.swift */; }; + F97B466224D9C7B500F4A88B /* KeychainStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B465E24D9C7B500F4A88B /* KeychainStore.swift */; }; + F97B466424D9C88600F4A88B /* SecureStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B466324D9C88600F4A88B /* SecureStorage.swift */; }; + F97B466524D9C88600F4A88B /* SecureStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B466324D9C88600F4A88B /* SecureStorage.swift */; }; + F97B466624D9C88600F4A88B /* SecureStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B466324D9C88600F4A88B /* SecureStorage.swift */; }; + F97B466724D9C88600F4A88B /* SecureStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B466324D9C88600F4A88B /* SecureStorage.swift */; }; + F97B466924D9C8C600F4A88B /* FindResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B466824D9C8C600F4A88B /* FindResult.swift */; }; + F97B466A24D9C8C600F4A88B /* FindResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B466824D9C8C600F4A88B /* FindResult.swift */; }; + F97B466B24D9C8C600F4A88B /* FindResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B466824D9C8C600F4A88B /* FindResult.swift */; }; + F97B466C24D9C8C600F4A88B /* FindResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B466824D9C8C600F4A88B /* FindResult.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -167,22 +198,7 @@ /* Begin PBXFileReference section */ 4A1120BF1F49FC3300E32D94 /* LinuxMain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinuxMain.swift; sourceTree = ""; }; - 4A2D8C801F48B3A900EE1FCC /* ParseEncoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseEncoder.swift; sourceTree = ""; }; - 4A2F14931F4A5E1E00A7A7EF /* ObjectType+Equatable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ObjectType+Equatable.swift"; sourceTree = ""; }; - 4A2F14951F4A5F2900A7A7EF /* Responses.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Responses.swift; sourceTree = ""; }; - 4A2F14971F4A5F6900A7A7EF /* ObjectType+Batch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ObjectType+Batch.swift"; sourceTree = ""; }; - 4A82B7EC1F254B820063D731 /* ObjectType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObjectType.swift; sourceTree = ""; }; - 4A82B7ED1F254B820063D731 /* GeoPoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeoPoint.swift; sourceTree = ""; }; 4A82B7EE1F254B820063D731 /* Parse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Parse.swift; sourceTree = ""; }; - 4A82B7F01F254B820063D731 /* File.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = File.swift; sourceTree = ""; }; - 4A82B7F11F254B820063D731 /* Pointer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pointer.swift; sourceTree = ""; }; - 4A82B7FE1F256A8F0063D731 /* Query.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Query.swift; sourceTree = ""; }; - 4A82B8001F256B330063D731 /* ObjectType+Query.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ObjectType+Query.swift"; sourceTree = ""; }; - 4A99A4681F2650CA00D72A59 /* ParseMutationContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseMutationContainer.swift; sourceTree = ""; }; - 4A99A46B1F2650FF00D72A59 /* AddUniqueOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddUniqueOperation.swift; sourceTree = ""; }; - 4A99A46D1F26512100D72A59 /* IncrementOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IncrementOperation.swift; sourceTree = ""; }; - 4AA8074A1F7930E9008CD551 /* SecureStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecureStorage.swift; sourceTree = ""; }; - 4AA8074D1F7931B7008CD551 /* KeychainStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainStore.swift; sourceTree = ""; }; 4AA807581F794242008CD551 /* TestHost.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestHost.app; sourceTree = BUILT_PRODUCTS_DIR; }; 4AA8075A1F794242008CD551 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 4AA8075F1F794242008CD551 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; @@ -191,30 +207,16 @@ 4AA807661F794242008CD551 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4AA8076D1F794C1C008CD551 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4AA8076E1F794C1C008CD551 /* KeychainStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainStoreTests.swift; sourceTree = ""; }; - 4AA8076F1F794C1C008CD551 /* ParseSwiftTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseSwiftTests.swift; sourceTree = ""; }; 4AB8B4F41F254AE10070F682 /* ParseSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ParseSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4AB8B4F71F254AE10070F682 /* Parse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Parse.h; sourceTree = ""; }; 4AB8B4F81F254AE10070F682 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4AB8B4FD1F254AE10070F682 /* ParseSwiftTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ParseSwiftTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 4AC3976F1F48778900DEA9D3 /* ACL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ACL.swift; sourceTree = ""; }; - 4AC397711F488F9E00DEA9D3 /* BatchUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatchUtils.swift; sourceTree = ""; }; - 4AC397731F488FF900DEA9D3 /* API.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = API.swift; sourceTree = ""; }; 4ACFC2E21F3CA21F0046F3A3 /* ParseSwift.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = ParseSwift.playground; sourceTree = ""; }; - 4AEBA5481F26519B00628B17 /* AddOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddOperation.swift; sourceTree = ""; }; - 4AEBA54A1F2651D900628B17 /* RemoveOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveOperation.swift; sourceTree = ""; }; - 4AEBA54C1F26523800628B17 /* DeleteOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeleteOperation.swift; sourceTree = ""; }; - 4AEBA54E1F265A0D00628B17 /* UserType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserType.swift; sourceTree = ""; }; - 4AF85BD21F78011100665264 /* ParseError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseError.swift; sourceTree = ""; }; - 4AF85BDC1F783B9800665264 /* API+Commands.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "API+Commands.swift"; sourceTree = ""; }; 4AFDA7121F26D9A5002AE4FC /* ParseSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ParseSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4AFDA7151F26D9A5002AE4FC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 709075C424B9117400B95310 /* AnyCodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyCodable.swift; sourceTree = ""; }; - 709075C524B9117500B95310 /* AnyDecodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyDecodable.swift; sourceTree = ""; }; - 709075C624B9117500B95310 /* AnyEncodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyEncodable.swift; sourceTree = ""; }; 70C7DC1D24D20E530050419B /* ParseUserCommandTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseUserCommandTests.swift; sourceTree = ""; }; 70C7DC1F24D20F180050419B /* ParseQueryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseQueryTests.swift; sourceTree = ""; }; 70C7DC2024D20F190050419B /* ParseObjectBatchTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseObjectBatchTests.swift; sourceTree = ""; }; - 70E5504224CA4E5F00F6D8D2 /* URLSession+extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "URLSession+extensions.swift"; sourceTree = ""; }; 7FFF552B2217E729007C3B4E /* AnyEncodableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyEncodableTests.swift; sourceTree = ""; }; 7FFF552C2217E729007C3B4E /* AnyCodableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyCodableTests.swift; sourceTree = ""; }; 7FFF552D2217E729007C3B4E /* AnyDecodableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyDecodableTests.swift; sourceTree = ""; }; @@ -228,6 +230,42 @@ 912C9BD824D3011F009947C3 /* ParseSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ParseSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 912C9BDA24D3011F009947C3 /* ParseSwift_tvOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ParseSwift_tvOS.h; sourceTree = ""; }; 912C9BDB24D3011F009947C3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + F97B45B424D9C6F200F4A88B /* ParseCoding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseCoding.swift; sourceTree = ""; }; + F97B45B524D9C6F200F4A88B /* AnyDecodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyDecodable.swift; sourceTree = ""; }; + F97B45B624D9C6F200F4A88B /* ParseEncoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseEncoder.swift; sourceTree = ""; }; + F97B45B724D9C6F200F4A88B /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; + F97B45B824D9C6F200F4A88B /* AnyCodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyCodable.swift; sourceTree = ""; }; + F97B45B924D9C6F200F4A88B /* AnyEncodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyEncodable.swift; sourceTree = ""; }; + F97B45BB24D9C6F200F4A88B /* Query.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Query.swift; sourceTree = ""; }; + F97B45BC24D9C6F200F4A88B /* GeoPoint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeoPoint.swift; sourceTree = ""; }; + F97B45BD24D9C6F200F4A88B /* BaseParseUser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseParseUser.swift; sourceTree = ""; }; + F97B45BE24D9C6F200F4A88B /* Pointer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Pointer.swift; sourceTree = ""; }; + F97B45BF24D9C6F200F4A88B /* ParseError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseError.swift; sourceTree = ""; }; + F97B45C024D9C6F200F4A88B /* ACL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ACL.swift; sourceTree = ""; }; + F97B45C124D9C6F200F4A88B /* File.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = File.swift; sourceTree = ""; }; + F97B45C224D9C6F200F4A88B /* NoBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoBody.swift; sourceTree = ""; }; + F97B45C424D9C6F200F4A88B /* ParseUser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseUser.swift; sourceTree = ""; }; + F97B45C524D9C6F200F4A88B /* Fetchable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Fetchable.swift; sourceTree = ""; }; + F97B45C624D9C6F200F4A88B /* ParseObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseObject.swift; sourceTree = ""; }; + F97B45C724D9C6F200F4A88B /* Saveable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Saveable.swift; sourceTree = ""; }; + F97B45C824D9C6F200F4A88B /* Queryable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Queryable.swift; sourceTree = ""; }; + F97B45CA24D9C6F200F4A88B /* URLSession+sync.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "URLSession+sync.swift"; sourceTree = ""; }; + F97B45CC24D9C6F200F4A88B /* ParseStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseStorage.swift; sourceTree = ""; }; + F97B45CD24D9C6F200F4A88B /* PrimitiveObjectStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrimitiveObjectStore.swift; sourceTree = ""; }; + F97B462624D9C72700F4A88B /* API.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = API.swift; sourceTree = ""; }; + F97B462B24D9C74400F4A88B /* BatchUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BatchUtils.swift; sourceTree = ""; }; + F97B462C24D9C74400F4A88B /* URLSession+extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "URLSession+extensions.swift"; sourceTree = ""; }; + F97B462D24D9C74400F4A88B /* Responses.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Responses.swift; sourceTree = ""; }; + F97B462E24D9C74400F4A88B /* API+Commands.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "API+Commands.swift"; sourceTree = ""; }; + F97B464024D9C78B00F4A88B /* ParseMutationContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseMutationContainer.swift; sourceTree = ""; }; + F97B464124D9C78B00F4A88B /* DeleteOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeleteOperation.swift; sourceTree = ""; }; + F97B464224D9C78B00F4A88B /* AddOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddOperation.swift; sourceTree = ""; }; + F97B464324D9C78B00F4A88B /* AddUniqueOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddUniqueOperation.swift; sourceTree = ""; }; + F97B464424D9C78B00F4A88B /* RemoveOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoveOperation.swift; sourceTree = ""; }; + F97B464524D9C78B00F4A88B /* IncrementOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IncrementOperation.swift; sourceTree = ""; }; + F97B465E24D9C7B500F4A88B /* KeychainStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeychainStore.swift; sourceTree = ""; }; + F97B466324D9C88600F4A88B /* SecureStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecureStorage.swift; sourceTree = ""; }; + F97B466824D9C8C600F4A88B /* FindResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FindResult.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -277,14 +315,6 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 4A2F149C1F4A604900A7A7EF /* Encoder */ = { - isa = PBXGroup; - children = ( - 4A2D8C801F48B3A900EE1FCC /* ParseEncoder.swift */, - ); - path = Encoder; - sourceTree = ""; - }; 4A5EE45F1F49E9E000D3CAE3 /* Sources */ = { isa = PBXGroup; children = ( @@ -310,42 +340,6 @@ path = "ParseSwift-iOS"; sourceTree = ""; }; - 4A82B7FD1F25691B0063D731 /* Types */ = { - isa = PBXGroup; - children = ( - 4AC3976F1F48778900DEA9D3 /* ACL.swift */, - 4AF85BD21F78011100665264 /* ParseError.swift */, - 4A82B7F01F254B820063D731 /* File.swift */, - 4A82B7ED1F254B820063D731 /* GeoPoint.swift */, - 4A82B7F11F254B820063D731 /* Pointer.swift */, - 4A82B7FE1F256A8F0063D731 /* Query.swift */, - ); - path = Types; - sourceTree = ""; - }; - 4A99A46A1F2650E200D72A59 /* Mutations */ = { - isa = PBXGroup; - children = ( - 4A99A4681F2650CA00D72A59 /* ParseMutationContainer.swift */, - 4AEBA5481F26519B00628B17 /* AddOperation.swift */, - 4AEBA54A1F2651D900628B17 /* RemoveOperation.swift */, - 4AEBA54C1F26523800628B17 /* DeleteOperation.swift */, - 4A99A46B1F2650FF00D72A59 /* AddUniqueOperation.swift */, - 4A99A46D1F26512100D72A59 /* IncrementOperation.swift */, - ); - name = Mutations; - path = MutationOperations; - sourceTree = ""; - }; - 4AA807491F7930D0008CD551 /* Storage */ = { - isa = PBXGroup; - children = ( - 4AA8074A1F7930E9008CD551 /* SecureStorage.swift */, - 4AA8074D1F7931B7008CD551 /* KeychainStore.swift */, - ); - path = Storage; - sourceTree = ""; - }; 4AA807591F794242008CD551 /* TestHost */ = { isa = PBXGroup; children = ( @@ -367,7 +361,6 @@ 70C7DC2024D20F190050419B /* ParseObjectBatchTests.swift */, 911DB13524C4FC100027F3C7 /* ParseObjectCommandTests.swift */, 70C7DC1F24D20F180050419B /* ParseQueryTests.swift */, - 4AA8076F1F794C1C008CD551 /* ParseSwiftTests.swift */, 70C7DC1D24D20E530050419B /* ParseUserCommandTests.swift */, 7FFF552A2217E729007C3B4E /* AnyCodableTests */, 911DB12A24C3F7260027F3C7 /* NetworkMocking */, @@ -406,43 +399,18 @@ 4AB8B4F61F254AE10070F682 /* ParseSwift */ = { isa = PBXGroup; children = ( + F97B45C924D9C6F200F4A88B /* API */, + F97B45B324D9C6F200F4A88B /* Coding */, + F97B463F24D9C78B00F4A88B /* Mutation Operations */, + F97B45C324D9C6F200F4A88B /* Objects */, + F97B45BA24D9C6F200F4A88B /* Parse Types */, + F97B45CB24D9C6F200F4A88B /* Storage */, 4A82B7EE1F254B820063D731 /* Parse.swift */, - 4AC397761F4895A200DEA9D3 /* Objects Protocols */, - 4A82B7FD1F25691B0063D731 /* Types */, - 709075CD24B9829600B95310 /* AnyCodable */, - 4A2F149C1F4A604900A7A7EF /* Encoder */, - 4A99A46A1F2650E200D72A59 /* Mutations */, - 4AC397771F4895C000DEA9D3 /* API */, - 4AA807491F7930D0008CD551 /* Storage */, 4AB8B4F71F254AE10070F682 /* Parse.h */, ); path = ParseSwift; sourceTree = ""; }; - 4AC397761F4895A200DEA9D3 /* Objects Protocols */ = { - isa = PBXGroup; - children = ( - 4A82B7EC1F254B820063D731 /* ObjectType.swift */, - 4A82B8001F256B330063D731 /* ObjectType+Query.swift */, - 4A2F14931F4A5E1E00A7A7EF /* ObjectType+Equatable.swift */, - 4A2F14971F4A5F6900A7A7EF /* ObjectType+Batch.swift */, - 4AEBA54E1F265A0D00628B17 /* UserType.swift */, - ); - path = "Objects Protocols"; - sourceTree = ""; - }; - 4AC397771F4895C000DEA9D3 /* API */ = { - isa = PBXGroup; - children = ( - 4AC397731F488FF900DEA9D3 /* API.swift */, - 4AF85BDC1F783B9800665264 /* API+Commands.swift */, - 4AC397711F488F9E00DEA9D3 /* BatchUtils.swift */, - 70E5504224CA4E5F00F6D8D2 /* URLSession+extensions.swift */, - 4A2F14951F4A5F2900A7A7EF /* Responses.swift */, - ); - path = API; - sourceTree = ""; - }; 4AFDA7131F26D9A5002AE4FC /* ParseSwift-macOS */ = { isa = PBXGroup; children = ( @@ -451,16 +419,6 @@ path = "ParseSwift-macOS"; sourceTree = ""; }; - 709075CD24B9829600B95310 /* AnyCodable */ = { - isa = PBXGroup; - children = ( - 709075C424B9117400B95310 /* AnyCodable.swift */, - 709075C524B9117500B95310 /* AnyDecodable.swift */, - 709075C624B9117500B95310 /* AnyEncodable.swift */, - ); - path = AnyCodable; - sourceTree = ""; - }; 7FFF552A2217E729007C3B4E /* AnyCodableTests */ = { isa = PBXGroup; children = ( @@ -498,6 +456,84 @@ path = "ParseSwift-tvOS"; sourceTree = ""; }; + F97B45B324D9C6F200F4A88B /* Coding */ = { + isa = PBXGroup; + children = ( + F97B45B424D9C6F200F4A88B /* ParseCoding.swift */, + F97B45B524D9C6F200F4A88B /* AnyDecodable.swift */, + F97B45B624D9C6F200F4A88B /* ParseEncoder.swift */, + F97B45B724D9C6F200F4A88B /* Extensions.swift */, + F97B45B824D9C6F200F4A88B /* AnyCodable.swift */, + F97B45B924D9C6F200F4A88B /* AnyEncodable.swift */, + ); + path = Coding; + sourceTree = ""; + }; + F97B45BA24D9C6F200F4A88B /* Parse Types */ = { + isa = PBXGroup; + children = ( + F97B45BB24D9C6F200F4A88B /* Query.swift */, + F97B45BC24D9C6F200F4A88B /* GeoPoint.swift */, + F97B45BD24D9C6F200F4A88B /* BaseParseUser.swift */, + F97B466824D9C8C600F4A88B /* FindResult.swift */, + F97B45BE24D9C6F200F4A88B /* Pointer.swift */, + F97B45BF24D9C6F200F4A88B /* ParseError.swift */, + F97B45C024D9C6F200F4A88B /* ACL.swift */, + F97B45C124D9C6F200F4A88B /* File.swift */, + F97B45C224D9C6F200F4A88B /* NoBody.swift */, + ); + path = "Parse Types"; + sourceTree = ""; + }; + F97B45C324D9C6F200F4A88B /* Objects */ = { + isa = PBXGroup; + children = ( + F97B45C424D9C6F200F4A88B /* ParseUser.swift */, + F97B45C524D9C6F200F4A88B /* Fetchable.swift */, + F97B45C624D9C6F200F4A88B /* ParseObject.swift */, + F97B45C724D9C6F200F4A88B /* Saveable.swift */, + F97B45C824D9C6F200F4A88B /* Queryable.swift */, + ); + path = Objects; + sourceTree = ""; + }; + F97B45C924D9C6F200F4A88B /* API */ = { + isa = PBXGroup; + children = ( + F97B462624D9C72700F4A88B /* API.swift */, + F97B462E24D9C74400F4A88B /* API+Commands.swift */, + F97B462B24D9C74400F4A88B /* BatchUtils.swift */, + F97B462D24D9C74400F4A88B /* Responses.swift */, + F97B462C24D9C74400F4A88B /* URLSession+extensions.swift */, + F97B45CA24D9C6F200F4A88B /* URLSession+sync.swift */, + ); + path = API; + sourceTree = ""; + }; + F97B45CB24D9C6F200F4A88B /* Storage */ = { + isa = PBXGroup; + children = ( + F97B465E24D9C7B500F4A88B /* KeychainStore.swift */, + F97B45CC24D9C6F200F4A88B /* ParseStorage.swift */, + F97B45CD24D9C6F200F4A88B /* PrimitiveObjectStore.swift */, + F97B466324D9C88600F4A88B /* SecureStorage.swift */, + ); + path = Storage; + sourceTree = ""; + }; + F97B463F24D9C78B00F4A88B /* Mutation Operations */ = { + isa = PBXGroup; + children = ( + F97B464024D9C78B00F4A88B /* ParseMutationContainer.swift */, + F97B464124D9C78B00F4A88B /* DeleteOperation.swift */, + F97B464224D9C78B00F4A88B /* AddOperation.swift */, + F97B464324D9C78B00F4A88B /* AddUniqueOperation.swift */, + F97B464424D9C78B00F4A88B /* RemoveOperation.swift */, + F97B464524D9C78B00F4A88B /* IncrementOperation.swift */, + ); + path = "Mutation Operations"; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -799,35 +835,43 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 4A2F14961F4A5F2900A7A7EF /* Responses.swift in Sources */, - 709075C724B9117500B95310 /* AnyCodable.swift in Sources */, - 4AC397741F488FF900DEA9D3 /* API.swift in Sources */, - 4A82B7F71F254CCE0063D731 /* ObjectType.swift in Sources */, - 70E5504324CA4E6000F6D8D2 /* URLSession+extensions.swift in Sources */, - 4A82B7F51F254CCE0063D731 /* GeoPoint.swift in Sources */, - 4AA8074B1F7930E9008CD551 /* SecureStorage.swift in Sources */, + F97B463724D9C74400F4A88B /* Responses.swift in Sources */, + F97B461624D9C6F200F4A88B /* Queryable.swift in Sources */, + F97B461A24D9C6F200F4A88B /* URLSession+sync.swift in Sources */, + F97B45DA24D9C6F200F4A88B /* Extensions.swift in Sources */, + F97B465F24D9C7B500F4A88B /* KeychainStore.swift in Sources */, + F97B465224D9C78C00F4A88B /* AddUniqueOperation.swift in Sources */, + F97B45D624D9C6F200F4A88B /* ParseEncoder.swift in Sources */, + F97B45F224D9C6F200F4A88B /* Pointer.swift in Sources */, + F97B461E24D9C6F200F4A88B /* ParseStorage.swift in Sources */, + F97B45D224D9C6F200F4A88B /* AnyDecodable.swift in Sources */, + F97B463B24D9C74400F4A88B /* API+Commands.swift in Sources */, + F97B464624D9C78B00F4A88B /* ParseMutationContainer.swift in Sources */, + F97B464A24D9C78B00F4A88B /* DeleteOperation.swift in Sources */, + F97B460624D9C6F200F4A88B /* ParseUser.swift in Sources */, + F97B465A24D9C78C00F4A88B /* IncrementOperation.swift in Sources */, + F97B45E224D9C6F200F4A88B /* AnyEncodable.swift in Sources */, + F97B466924D9C8C600F4A88B /* FindResult.swift in Sources */, + F97B462224D9C6F200F4A88B /* PrimitiveObjectStore.swift in Sources */, + F97B45E624D9C6F200F4A88B /* Query.swift in Sources */, + F97B466424D9C88600F4A88B /* SecureStorage.swift in Sources */, + F97B462F24D9C74400F4A88B /* BatchUtils.swift in Sources */, 4A82B7F61F254CCE0063D731 /* Parse.swift in Sources */, - 4AEBA54F1F265A0D00628B17 /* UserType.swift in Sources */, - 4A99A4691F2650CA00D72A59 /* ParseMutationContainer.swift in Sources */, - 4AC397701F48778900DEA9D3 /* ACL.swift in Sources */, - 4A2D8C811F48B3A900EE1FCC /* ParseEncoder.swift in Sources */, - 4A99A46E1F26512100D72A59 /* IncrementOperation.swift in Sources */, - 4A82B8011F256B330063D731 /* ObjectType+Query.swift in Sources */, - 4A82B7FF1F256A8F0063D731 /* Query.swift in Sources */, - 4A2F14981F4A5F6900A7A7EF /* ObjectType+Batch.swift in Sources */, - 709075CB24B9117500B95310 /* AnyEncodable.swift in Sources */, - 4A82B7F41F254CCE0063D731 /* File.swift in Sources */, - 4AF85BD31F78011100665264 /* ParseError.swift in Sources */, - 4AA8074E1F7931B7008CD551 /* KeychainStore.swift in Sources */, - 4A2F14941F4A5E1E00A7A7EF /* ObjectType+Equatable.swift in Sources */, - 4AC397721F488F9E00DEA9D3 /* BatchUtils.swift in Sources */, - 4AEBA54D1F26523800628B17 /* DeleteOperation.swift in Sources */, - 4AF85BDD1F783B9800665264 /* API+Commands.swift in Sources */, - 4A82B7F81F254CCE0063D731 /* Pointer.swift in Sources */, - 709075C924B9117500B95310 /* AnyDecodable.swift in Sources */, - 4AEBA5491F26519B00628B17 /* AddOperation.swift in Sources */, - 4A99A46C1F2650FF00D72A59 /* AddUniqueOperation.swift in Sources */, - 4AEBA54B1F2651D900628B17 /* RemoveOperation.swift in Sources */, + F97B45EA24D9C6F200F4A88B /* GeoPoint.swift in Sources */, + F97B460224D9C6F200F4A88B /* NoBody.swift in Sources */, + F97B45F624D9C6F200F4A88B /* ParseError.swift in Sources */, + F97B463324D9C74400F4A88B /* URLSession+extensions.swift in Sources */, + F97B464E24D9C78B00F4A88B /* AddOperation.swift in Sources */, + F97B45FE24D9C6F200F4A88B /* File.swift in Sources */, + F97B45EE24D9C6F200F4A88B /* BaseParseUser.swift in Sources */, + F97B460A24D9C6F200F4A88B /* Fetchable.swift in Sources */, + F97B460E24D9C6F200F4A88B /* ParseObject.swift in Sources */, + F97B461224D9C6F200F4A88B /* Saveable.swift in Sources */, + F97B45CE24D9C6F200F4A88B /* ParseCoding.swift in Sources */, + F97B465624D9C78C00F4A88B /* RemoveOperation.swift in Sources */, + F97B45FA24D9C6F200F4A88B /* ACL.swift in Sources */, + F97B462724D9C72700F4A88B /* API.swift in Sources */, + F97B45DE24D9C6F200F4A88B /* AnyCodable.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -843,7 +887,6 @@ 70C7DC2224D20F190050419B /* ParseObjectBatchTests.swift in Sources */, 7FFF552F2217E72A007C3B4E /* AnyCodableTests.swift in Sources */, 4AA807701F794C31008CD551 /* KeychainStoreTests.swift in Sources */, - 4AA807711F794C33008CD551 /* ParseSwiftTests.swift in Sources */, 70C7DC2124D20F190050419B /* ParseQueryTests.swift in Sources */, 70C7DC1E24D20E530050419B /* ParseUserCommandTests.swift in Sources */, 911DB13324C494390027F3C7 /* MockURLProtocol.swift in Sources */, @@ -854,35 +897,43 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 4AFDA72B1F26DAE1002AE4FC /* ObjectType.swift in Sources */, - 709075C824B9117500B95310 /* AnyCodable.swift in Sources */, - 4AFDA7301F26DAE1002AE4FC /* DeleteOperation.swift in Sources */, - 4AFDA7361F26DAE1002AE4FC /* ObjectType+Query.swift in Sources */, - 70E5504424CA4E6000F6D8D2 /* URLSession+extensions.swift in Sources */, - 4AFDA7341F26DAE1002AE4FC /* Pointer.swift in Sources */, - 4AA8074C1F7930E9008CD551 /* SecureStorage.swift in Sources */, - 4A6511501F48E400005237DF /* BatchUtils.swift in Sources */, + F97B463824D9C74400F4A88B /* Responses.swift in Sources */, + F97B461724D9C6F200F4A88B /* Queryable.swift in Sources */, + F97B461B24D9C6F200F4A88B /* URLSession+sync.swift in Sources */, + F97B45DB24D9C6F200F4A88B /* Extensions.swift in Sources */, + F97B466024D9C7B500F4A88B /* KeychainStore.swift in Sources */, + F97B465324D9C78C00F4A88B /* AddUniqueOperation.swift in Sources */, + F97B45D724D9C6F200F4A88B /* ParseEncoder.swift in Sources */, + F97B45F324D9C6F200F4A88B /* Pointer.swift in Sources */, + F97B461F24D9C6F200F4A88B /* ParseStorage.swift in Sources */, + F97B45D324D9C6F200F4A88B /* AnyDecodable.swift in Sources */, + F97B463C24D9C74400F4A88B /* API+Commands.swift in Sources */, + F97B464724D9C78B00F4A88B /* ParseMutationContainer.swift in Sources */, + F97B464B24D9C78B00F4A88B /* DeleteOperation.swift in Sources */, + F97B460724D9C6F200F4A88B /* ParseUser.swift in Sources */, + F97B465B24D9C78C00F4A88B /* IncrementOperation.swift in Sources */, + F97B45E324D9C6F200F4A88B /* AnyEncodable.swift in Sources */, + F97B466A24D9C8C600F4A88B /* FindResult.swift in Sources */, + F97B462324D9C6F200F4A88B /* PrimitiveObjectStore.swift in Sources */, + F97B45E724D9C6F200F4A88B /* Query.swift in Sources */, + F97B466524D9C88600F4A88B /* SecureStorage.swift in Sources */, + F97B463024D9C74400F4A88B /* BatchUtils.swift in Sources */, 4AFDA72A1F26DAE1002AE4FC /* Parse.swift in Sources */, - 4AFDA7351F26DAE1002AE4FC /* Query.swift in Sources */, - 4A2F14991F4A5FB500A7A7EF /* Responses.swift in Sources */, - 4A2F149A1F4A5FBA00A7A7EF /* ObjectType+Equatable.swift in Sources */, - 4A65114F1F48E3F3005237DF /* ParseEncoder.swift in Sources */, - 4AFDA72E1F26DAE1002AE4FC /* AddOperation.swift in Sources */, - 4AFDA7311F26DAE1002AE4FC /* AddUniqueOperation.swift in Sources */, - 4A2F149B1F4A5FBA00A7A7EF /* ObjectType+Batch.swift in Sources */, - 709075CC24B9117500B95310 /* AnyEncodable.swift in Sources */, - 4A6511521F48E406005237DF /* GeoPoint.swift in Sources */, - 4AF85BD61F7803C100665264 /* ParseError.swift in Sources */, - 4AA8074F1F7931B7008CD551 /* KeychainStore.swift in Sources */, - 4AFDA7331F26DAE1002AE4FC /* File.swift in Sources */, - 4A6511531F48E410005237DF /* API.swift in Sources */, - 4AFDA7321F26DAE1002AE4FC /* IncrementOperation.swift in Sources */, - 4AF85BDE1F783BB400665264 /* API+Commands.swift in Sources */, - 4AFDA72D1F26DAE1002AE4FC /* ParseMutationContainer.swift in Sources */, - 709075CA24B9117500B95310 /* AnyDecodable.swift in Sources */, - 4AFDA72C1F26DAE1002AE4FC /* UserType.swift in Sources */, - 4A6511511F48E406005237DF /* ACL.swift in Sources */, - 4AFDA72F1F26DAE1002AE4FC /* RemoveOperation.swift in Sources */, + F97B45EB24D9C6F200F4A88B /* GeoPoint.swift in Sources */, + F97B460324D9C6F200F4A88B /* NoBody.swift in Sources */, + F97B45F724D9C6F200F4A88B /* ParseError.swift in Sources */, + F97B463424D9C74400F4A88B /* URLSession+extensions.swift in Sources */, + F97B464F24D9C78B00F4A88B /* AddOperation.swift in Sources */, + F97B45FF24D9C6F200F4A88B /* File.swift in Sources */, + F97B45EF24D9C6F200F4A88B /* BaseParseUser.swift in Sources */, + F97B460B24D9C6F200F4A88B /* Fetchable.swift in Sources */, + F97B460F24D9C6F200F4A88B /* ParseObject.swift in Sources */, + F97B461324D9C6F200F4A88B /* Saveable.swift in Sources */, + F97B45CF24D9C6F200F4A88B /* ParseCoding.swift in Sources */, + F97B465724D9C78C00F4A88B /* RemoveOperation.swift in Sources */, + F97B45FB24D9C6F200F4A88B /* ACL.swift in Sources */, + F97B462824D9C72700F4A88B /* API.swift in Sources */, + F97B45DF24D9C6F200F4A88B /* AnyCodable.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -890,36 +941,44 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 912C9C1724D302B2009947C3 /* Responses.swift in Sources */, - 912C9C1024D302B2009947C3 /* DeleteOperation.swift in Sources */, - 912C9C1824D302B2009947C3 /* SecureStorage.swift in Sources */, - 912C9C0924D302B2009947C3 /* AnyCodable.swift in Sources */, - 912C9C0B24D302B2009947C3 /* AnyEncodable.swift in Sources */, - 912C9C0424D302B2009947C3 /* ParseError.swift in Sources */, - 912C9BFE24D302B2009947C3 /* ObjectType.swift in Sources */, + F97B45D524D9C6F200F4A88B /* AnyDecodable.swift in Sources */, + F97B45E924D9C6F200F4A88B /* Query.swift in Sources */, + F97B463624D9C74400F4A88B /* URLSession+extensions.swift in Sources */, + F97B460524D9C6F200F4A88B /* NoBody.swift in Sources */, + F97B45E124D9C6F200F4A88B /* AnyCodable.swift in Sources */, + F97B45E524D9C6F200F4A88B /* AnyEncodable.swift in Sources */, + F97B465D24D9C78C00F4A88B /* IncrementOperation.swift in Sources */, + F97B45FD24D9C6F200F4A88B /* ACL.swift in Sources */, + F97B465124D9C78C00F4A88B /* AddOperation.swift in Sources */, + F97B461124D9C6F200F4A88B /* ParseObject.swift in Sources */, + F97B460D24D9C6F200F4A88B /* Fetchable.swift in Sources */, + F97B45ED24D9C6F200F4A88B /* GeoPoint.swift in Sources */, + F97B45F524D9C6F200F4A88B /* Pointer.swift in Sources */, + F97B460924D9C6F200F4A88B /* ParseUser.swift in Sources */, + F97B463A24D9C74400F4A88B /* Responses.swift in Sources */, + F97B466C24D9C8C600F4A88B /* FindResult.swift in Sources */, + F97B45DD24D9C6F200F4A88B /* Extensions.swift in Sources */, + F97B462124D9C6F200F4A88B /* ParseStorage.swift in Sources */, + F97B466724D9C88600F4A88B /* SecureStorage.swift in Sources */, 912C9C1624D302B2009947C3 /* (null) in Sources */, - 912C9C0724D302B2009947C3 /* Pointer.swift in Sources */, - 912C9C1124D302B2009947C3 /* AddUniqueOperation.swift in Sources */, - 912C9C0124D302B2009947C3 /* ObjectType+Batch.swift in Sources */, - 912C9C0824D302B2009947C3 /* Query.swift in Sources */, - 912C9C0E24D302B2009947C3 /* AddOperation.swift in Sources */, - 912C9C0224D302B2009947C3 /* UserType.swift in Sources */, - 912C9C1524D302B2009947C3 /* BatchUtils.swift in Sources */, - 912C9C0F24D302B2009947C3 /* RemoveOperation.swift in Sources */, - 912C9C1424D302B2009947C3 /* API+Commands.swift in Sources */, - 912C9C0C24D302B2009947C3 /* ParseEncoder.swift in Sources */, - 912C9C0624D302B2009947C3 /* GeoPoint.swift in Sources */, - 912C9C0024D302B2009947C3 /* ObjectType+Equatable.swift in Sources */, - 912C9C1324D302B2009947C3 /* API.swift in Sources */, - 912C9C0324D302B2009947C3 /* ACL.swift in Sources */, - 912C9BFF24D302B2009947C3 /* ObjectType+Query.swift in Sources */, - 912C9C0524D302B2009947C3 /* File.swift in Sources */, - 912C9C0A24D302B2009947C3 /* AnyDecodable.swift in Sources */, - 912C9C1224D302B2009947C3 /* IncrementOperation.swift in Sources */, - 70C7DC2424D620330050419B /* URLSession+extensions.swift in Sources */, + F97B465924D9C78C00F4A88B /* RemoveOperation.swift in Sources */, + F97B45F924D9C6F200F4A88B /* ParseError.swift in Sources */, + F97B460124D9C6F200F4A88B /* File.swift in Sources */, + F97B464924D9C78B00F4A88B /* ParseMutationContainer.swift in Sources */, + F97B45D124D9C6F200F4A88B /* ParseCoding.swift in Sources */, + F97B465524D9C78C00F4A88B /* AddUniqueOperation.swift in Sources */, + F97B464D24D9C78B00F4A88B /* DeleteOperation.swift in Sources */, + F97B461524D9C6F200F4A88B /* Saveable.swift in Sources */, + F97B462524D9C6F200F4A88B /* PrimitiveObjectStore.swift in Sources */, + F97B466224D9C7B500F4A88B /* KeychainStore.swift in Sources */, + F97B463E24D9C74400F4A88B /* API+Commands.swift in Sources */, + F97B462A24D9C72700F4A88B /* API.swift in Sources */, + F97B463224D9C74400F4A88B /* BatchUtils.swift in Sources */, + F97B461D24D9C6F200F4A88B /* URLSession+sync.swift in Sources */, + F97B45F124D9C6F200F4A88B /* BaseParseUser.swift in Sources */, + F97B45D924D9C6F200F4A88B /* ParseEncoder.swift in Sources */, 912C9BFD24D302B2009947C3 /* Parse.swift in Sources */, - 912C9C0D24D302B2009947C3 /* ParseMutationContainer.swift in Sources */, - 912C9C1924D302B2009947C3 /* KeychainStore.swift in Sources */, + F97B461924D9C6F200F4A88B /* Queryable.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -927,36 +986,44 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 912C9BFA24D302B0009947C3 /* Responses.swift in Sources */, - 912C9BF324D302B0009947C3 /* DeleteOperation.swift in Sources */, - 912C9BFB24D302B0009947C3 /* SecureStorage.swift in Sources */, - 912C9BEC24D302B0009947C3 /* AnyCodable.swift in Sources */, - 912C9BEE24D302B0009947C3 /* AnyEncodable.swift in Sources */, - 912C9BE724D302B0009947C3 /* ParseError.swift in Sources */, - 912C9BE124D302B0009947C3 /* ObjectType.swift in Sources */, + F97B45D424D9C6F200F4A88B /* AnyDecodable.swift in Sources */, + F97B45E824D9C6F200F4A88B /* Query.swift in Sources */, + F97B463524D9C74400F4A88B /* URLSession+extensions.swift in Sources */, + F97B460424D9C6F200F4A88B /* NoBody.swift in Sources */, + F97B45E024D9C6F200F4A88B /* AnyCodable.swift in Sources */, + F97B45E424D9C6F200F4A88B /* AnyEncodable.swift in Sources */, + F97B465C24D9C78C00F4A88B /* IncrementOperation.swift in Sources */, + F97B45FC24D9C6F200F4A88B /* ACL.swift in Sources */, + F97B465024D9C78B00F4A88B /* AddOperation.swift in Sources */, + F97B461024D9C6F200F4A88B /* ParseObject.swift in Sources */, + F97B460C24D9C6F200F4A88B /* Fetchable.swift in Sources */, + F97B45EC24D9C6F200F4A88B /* GeoPoint.swift in Sources */, + F97B45F424D9C6F200F4A88B /* Pointer.swift in Sources */, + F97B460824D9C6F200F4A88B /* ParseUser.swift in Sources */, + F97B463924D9C74400F4A88B /* Responses.swift in Sources */, + F97B466B24D9C8C600F4A88B /* FindResult.swift in Sources */, + F97B45DC24D9C6F200F4A88B /* Extensions.swift in Sources */, + F97B462024D9C6F200F4A88B /* ParseStorage.swift in Sources */, + F97B466624D9C88600F4A88B /* SecureStorage.swift in Sources */, 912C9BF924D302B0009947C3 /* (null) in Sources */, - 912C9BEA24D302B0009947C3 /* Pointer.swift in Sources */, - 912C9BF424D302B0009947C3 /* AddUniqueOperation.swift in Sources */, - 912C9BE424D302B0009947C3 /* ObjectType+Batch.swift in Sources */, - 912C9BEB24D302B0009947C3 /* Query.swift in Sources */, - 912C9BF124D302B0009947C3 /* AddOperation.swift in Sources */, - 912C9BE524D302B0009947C3 /* UserType.swift in Sources */, - 912C9BF824D302B0009947C3 /* BatchUtils.swift in Sources */, - 912C9BF224D302B0009947C3 /* RemoveOperation.swift in Sources */, - 912C9BF724D302B0009947C3 /* API+Commands.swift in Sources */, - 912C9BEF24D302B0009947C3 /* ParseEncoder.swift in Sources */, - 912C9BE924D302B0009947C3 /* GeoPoint.swift in Sources */, - 912C9BE324D302B0009947C3 /* ObjectType+Equatable.swift in Sources */, - 912C9BF624D302B0009947C3 /* API.swift in Sources */, - 912C9BE624D302B0009947C3 /* ACL.swift in Sources */, - 912C9BE224D302B0009947C3 /* ObjectType+Query.swift in Sources */, - 912C9BE824D302B0009947C3 /* File.swift in Sources */, - 912C9BED24D302B0009947C3 /* AnyDecodable.swift in Sources */, - 912C9BF524D302B0009947C3 /* IncrementOperation.swift in Sources */, - 70C7DC2324D620300050419B /* URLSession+extensions.swift in Sources */, + F97B465824D9C78C00F4A88B /* RemoveOperation.swift in Sources */, + F97B45F824D9C6F200F4A88B /* ParseError.swift in Sources */, + F97B460024D9C6F200F4A88B /* File.swift in Sources */, + F97B464824D9C78B00F4A88B /* ParseMutationContainer.swift in Sources */, + F97B45D024D9C6F200F4A88B /* ParseCoding.swift in Sources */, + F97B465424D9C78C00F4A88B /* AddUniqueOperation.swift in Sources */, + F97B464C24D9C78B00F4A88B /* DeleteOperation.swift in Sources */, + F97B461424D9C6F200F4A88B /* Saveable.swift in Sources */, + F97B462424D9C6F200F4A88B /* PrimitiveObjectStore.swift in Sources */, + F97B466124D9C7B500F4A88B /* KeychainStore.swift in Sources */, + F97B463D24D9C74400F4A88B /* API+Commands.swift in Sources */, + F97B462924D9C72700F4A88B /* API.swift in Sources */, + F97B463124D9C74400F4A88B /* BatchUtils.swift in Sources */, + F97B461C24D9C6F200F4A88B /* URLSession+sync.swift in Sources */, + F97B45F024D9C6F200F4A88B /* BaseParseUser.swift in Sources */, + F97B45D824D9C6F200F4A88B /* ParseEncoder.swift in Sources */, 912C9BE024D302B0009947C3 /* Parse.swift in Sources */, - 912C9BF024D302B0009947C3 /* ParseMutationContainer.swift in Sources */, - 912C9BFC24D302B0009947C3 /* KeychainStore.swift in Sources */, + F97B461824D9C6F200F4A88B /* Queryable.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Sources/ParseSwift/API/API+Commands.swift b/Sources/ParseSwift/API/API+Commands.swift index a052e82ea..7823619f3 100644 --- a/Sources/ParseSwift/API/API+Commands.swift +++ b/Sources/ParseSwift/API/API+Commands.swift @@ -19,7 +19,7 @@ internal extension API { let params: [String: String?]? internal var data: Data? { - return try? getJSONEncoder().encode(body) + return try? ParseCoding.jsonEncoder().encode(body) } init(method: API.Method, @@ -94,7 +94,7 @@ internal extension API { internal extension API.Command { // MARK: Saving - static func saveCommand(_ object: T) -> API.Command where T: ObjectType { + static func saveCommand(_ object: T) -> API.Command where T: ParseObject { if object.isSaved { return updateCommand(object) } @@ -102,9 +102,9 @@ internal extension API.Command { } // MARK: Saving - private - private static func createCommand(_ object: T) -> API.Command where T: ObjectType { + private static func createCommand(_ object: T) -> API.Command where T: ParseObject { let mapper = { (data) -> T in - try getDecoder().decode(SaveResponse.self, from: data).apply(to: object) + try ParseCoding.jsonDecoder().decode(SaveResponse.self, from: data).apply(to: object) } return API.Command(method: .POST, path: object.endpoint, @@ -112,9 +112,9 @@ internal extension API.Command { mapper: mapper) } - private static func updateCommand(_ object: T) -> API.Command where T: ObjectType { + private static func updateCommand(_ object: T) -> API.Command where T: ParseObject { let mapper = { (data: Data) -> T in - try getDecoder().decode(UpdateResponse.self, from: data).apply(to: object) + try ParseCoding.jsonDecoder().decode(UpdateResponse.self, from: data).apply(to: object) } return API.Command(method: .PUT, path: object.endpoint, @@ -123,18 +123,21 @@ internal extension API.Command { } // MARK: Fetching - static func fetchCommand(_ object: T) throws -> API.Command where T: ObjectType { + static func fetchCommand(_ object: T) throws -> API.Command where T: ParseObject { guard object.isSaved else { throw ParseError(code: .unknownError, message: "Cannot Fetch an object without id") } - return API.Command(method: .GET, - path: object.endpoint) { (data) -> T in - try getDecoder().decode(FetchResponse.self, from: data).apply(to: object) + + return API.Command( + method: .GET, + path: object.endpoint + ) { (data) -> T in + try ParseCoding.jsonDecoder().decode(FetchResponse.self, from: data).apply(to: object) } } } -extension API.Command where T: ObjectType { +extension API.Command where T: ParseObject { internal var data: Data? { guard let body = body else { return nil } @@ -159,7 +162,7 @@ extension API.Command where T: ObjectType { let mapper = { (data: Data) -> [Result] in let decodingType = [BatchResponseItem].self do { - let responses = try getDecoder().decode(decodingType, from: data) + let responses = try ParseCoding.jsonDecoder().decode(decodingType, from: data) return bodies.enumerated().map({ (object) -> (Result) in let response = responses[object.offset] if let success = response.success { diff --git a/Sources/ParseSwift/API/BatchUtils.swift b/Sources/ParseSwift/API/BatchUtils.swift index 4b94a41c4..b6e12d196 100644 --- a/Sources/ParseSwift/API/BatchUtils.swift +++ b/Sources/ParseSwift/API/BatchUtils.swift @@ -8,10 +8,10 @@ import Foundation -typealias ParseObjectBatchCommand = BatchCommand where T: ObjectType +typealias ParseObjectBatchCommand = BatchCommand where T: ParseObject typealias ParseObjectBatchResponse = [(Result)] // swiftlint:disable line_length -typealias RESTBatchCommandType = API.Command, ParseObjectBatchResponse> where T: ObjectType +typealias RESTBatchCommandType = API.Command, ParseObjectBatchResponse> where T: ParseObject // swiftlint:enable line_length internal struct BatchCommand: Encodable where T: Encodable { @@ -49,7 +49,7 @@ internal struct WriteResponse: Codable { return FetchResponse(createdAt: createdAt, updatedAt: updatedAt) } - func apply(to object: T, method: API.Method) -> T where T: ObjectType { + func apply(to object: T, method: API.Method) -> T where T: ParseObject { switch method { case .POST: return asSaveResponse().apply(to: object) diff --git a/Sources/ParseSwift/API/Responses.swift b/Sources/ParseSwift/API/Responses.swift index e0e979b3d..a88a0ffa4 100644 --- a/Sources/ParseSwift/API/Responses.swift +++ b/Sources/ParseSwift/API/Responses.swift @@ -15,7 +15,7 @@ internal struct SaveResponse: Decodable { return createdAt } - func apply(to object: T) -> T where T: ObjectType { + func apply(to object: T) -> T where T: ParseObject { var object = object object.objectId = objectId object.createdAt = createdAt @@ -27,7 +27,7 @@ internal struct SaveResponse: Decodable { internal struct UpdateResponse: Decodable { var updatedAt: Date - func apply(to object: T) -> T where T: ObjectType { + func apply(to object: T) -> T where T: ParseObject { var object = object object.updatedAt = updatedAt return object @@ -38,7 +38,7 @@ internal struct FetchResponse: Decodable { var createdAt: Date var updatedAt: Date - func apply(to object: T) -> T where T: ObjectType { + func apply(to object: T) -> T where T: ParseObject { var object = object object.createdAt = createdAt object.updatedAt = updatedAt diff --git a/Sources/ParseSwift/API/URLSession+extensions.swift b/Sources/ParseSwift/API/URLSession+extensions.swift index 06b5ee8ee..a46434cf2 100755 --- a/Sources/ParseSwift/API/URLSession+extensions.swift +++ b/Sources/ParseSwift/API/URLSession+extensions.swift @@ -23,7 +23,7 @@ extension URLSession { do { return try .success(mapper(responseData)) } catch { - let parseError = try? getDecoder().decode(ParseError.self, from: responseData) + let parseError = try? ParseCoding.jsonDecoder().decode(ParseError.self, from: responseData) return .failure(parseError ?? ParseError(code: .unknownError, message: "cannot decode error")) } } else if let responseError = responseError { diff --git a/Sources/ParseSwift/Coding/Extensions.swift b/Sources/ParseSwift/Coding/Extensions.swift index 205d6b8dd..f9c1e0f4e 100644 --- a/Sources/ParseSwift/Coding/Extensions.swift +++ b/Sources/ParseSwift/Coding/Extensions.swift @@ -34,4 +34,8 @@ internal extension ParseObject { func getEncoder(skipKeys: Bool = true) -> ParseEncoder { return ParseCoding.parseEncoder(skipKeys: skipKeys) } + + func getTestDecoder() -> JSONDecoder { + ParseCoding.jsonDecoder() + } } diff --git a/Sources/ParseSwift/Coding/ParseCoding.swift b/Sources/ParseSwift/Coding/ParseCoding.swift index 066eba6f0..4cc3bb658 100644 --- a/Sources/ParseSwift/Coding/ParseCoding.swift +++ b/Sources/ParseSwift/Coding/ParseCoding.swift @@ -1,5 +1,5 @@ // -// ParseObjectType.swift +// ParseParseObject.swift // ParseSwift // // Created by Florent Vilmart on 17-07-24. diff --git a/Sources/ParseSwift/MutationOperations/AddOperation.swift b/Sources/ParseSwift/Mutation Operations/AddOperation.swift similarity index 100% rename from Sources/ParseSwift/MutationOperations/AddOperation.swift rename to Sources/ParseSwift/Mutation Operations/AddOperation.swift diff --git a/Sources/ParseSwift/MutationOperations/AddUniqueOperation.swift b/Sources/ParseSwift/Mutation Operations/AddUniqueOperation.swift similarity index 100% rename from Sources/ParseSwift/MutationOperations/AddUniqueOperation.swift rename to Sources/ParseSwift/Mutation Operations/AddUniqueOperation.swift diff --git a/Sources/ParseSwift/MutationOperations/DeleteOperation.swift b/Sources/ParseSwift/Mutation Operations/DeleteOperation.swift similarity index 100% rename from Sources/ParseSwift/MutationOperations/DeleteOperation.swift rename to Sources/ParseSwift/Mutation Operations/DeleteOperation.swift diff --git a/Sources/ParseSwift/MutationOperations/IncrementOperation.swift b/Sources/ParseSwift/Mutation Operations/IncrementOperation.swift similarity index 100% rename from Sources/ParseSwift/MutationOperations/IncrementOperation.swift rename to Sources/ParseSwift/Mutation Operations/IncrementOperation.swift diff --git a/Sources/ParseSwift/MutationOperations/ParseMutationContainer.swift b/Sources/ParseSwift/Mutation Operations/ParseMutationContainer.swift similarity index 100% rename from Sources/ParseSwift/MutationOperations/ParseMutationContainer.swift rename to Sources/ParseSwift/Mutation Operations/ParseMutationContainer.swift diff --git a/Sources/ParseSwift/MutationOperations/RemoveOperation.swift b/Sources/ParseSwift/Mutation Operations/RemoveOperation.swift similarity index 100% rename from Sources/ParseSwift/MutationOperations/RemoveOperation.swift rename to Sources/ParseSwift/Mutation Operations/RemoveOperation.swift diff --git a/Sources/ParseSwift/Objects Protocols/ObjectType+Batch.swift b/Sources/ParseSwift/Objects Protocols/ObjectType+Batch.swift deleted file mode 100644 index 2498bc080..000000000 --- a/Sources/ParseSwift/Objects Protocols/ObjectType+Batch.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// ObjectType+Batch.swift -// ParseSwift -// -// Created by Florent Vilmart on 17-08-20. -// Copyright © 2017 Parse. All rights reserved. -// - -import Foundation - -public extension ObjectType { - static func saveAll(_ objects: Self...) throws -> [(Result)] { - return try objects.saveAll() - } - - static func saveAll(options: API.Options = [], - _ objects: Self..., - completion: @escaping (Result<[(Result)], ParseError>) -> Void) { - objects.saveAll(options: options, completion: completion) - } -} - -extension Sequence where Element: ObjectType { - public func saveAll(options: API.Options = []) throws -> [(Result)] { - let commands = map { $0.saveCommand() } - return try API.Command - .batch(commands: commands) - .execute(options: options) - } - - public func saveAll(options: API.Options = [], callbackQueue: DispatchQueue = .main, - completion: @escaping (Result<[(Result)], ParseError>) -> Void) { - let commands = map { $0.saveCommand() } - API.Command - .batch(commands: commands) - .executeAsync(options: options, callbackQueue: callbackQueue, completion: completion) - } -} diff --git a/Sources/ParseSwift/Objects Protocols/ObjectType+Query.swift b/Sources/ParseSwift/Objects Protocols/ObjectType+Query.swift deleted file mode 100644 index b25b22270..000000000 --- a/Sources/ParseSwift/Objects Protocols/ObjectType+Query.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// Object+Query.swift -// Parse -// -// Created by Florent Vilmart on 17-07-23. -// Copyright © 2020 Parse Community. All rights reserved. -// - -import Foundation - -public extension ObjectType { - static func find() throws -> [Self] { - return try query().find() - } - - static func query() -> Query { - return Query() - } - - static func query(_ constraints: QueryConstraint...) -> Query { - return Query(constraints) - } -} diff --git a/Sources/ParseSwift/Objects Protocols/ObjectType.swift b/Sources/ParseSwift/Objects Protocols/ObjectType.swift deleted file mode 100644 index 36cd365e1..000000000 --- a/Sources/ParseSwift/Objects Protocols/ObjectType.swift +++ /dev/null @@ -1,236 +0,0 @@ -// -// ParseObjectType.swift -// ParseSwift -// -// Created by Florent Vilmart on 17-07-24. -// Copyright © 2020 Parse Community. All rights reserved. -// - -import Foundation - -public struct NoBody: Codable {} - -public protocol Saving: Codable { - associatedtype SavingType - func save(options: API.Options) throws -> SavingType - func save() throws -> SavingType -} - -extension Saving { - public func save() throws -> SavingType { - return try save(options: []) - } -} - -public protocol Fetching: Codable { - associatedtype FetchingType - func fetch(options: API.Options) throws -> FetchingType - func fetch() throws -> FetchingType -} - -extension Fetching { - public func fetch() throws -> FetchingType { - return try fetch(options: []) - } -} - -public protocol ObjectType: Fetching, Saving, CustomDebugStringConvertible, Equatable { - static var className: String { get } - var objectId: String? { get set } - var createdAt: Date? { get set } - var updatedAt: Date? { get set } - var ACL: ACL? { get set } -} - -internal extension ObjectType { - func getEncoder() -> ParseEncoder { - return getParseEncoder() - } - - func getTestDecoder() -> JSONDecoder { - return getDecoder() - } - - func getEncoderWithoutSkippingKeys() -> ParseEncoder { - return getParseEncoderWithoutSkippingKeys() - } -} - -extension ObjectType { - // Parse ClassName inference - public static var className: String { - let classType = "\(type(of: self))" - return classType.components(separatedBy: ".").first! // strip .Type - } - public var className: String { - return Self.className - } -} - -extension ObjectType { - public var debugDescription: String { - guard let descriptionData = try? getJSONEncoder().encode(self), - let descriptionString = String(data: descriptionData, encoding: .utf8) else { - return "\(className) ()" - } - return "\(className) (\(descriptionString))" - } -} - -public extension ObjectType { - func toPointer() -> Pointer { - return Pointer(self) - } -} - -enum DateEncodingKeys: String, CodingKey { - case iso - case type = "__type" -} - -let dateFormatter: DateFormatter = { - var dateFormatter = DateFormatter() - dateFormatter.locale = Locale(identifier: "") - dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" - return dateFormatter -}() - -let parseDateEncodingStrategy: ParseEncoder.DateEncodingStrategy = .custom({ (date, enc) in - var container = enc.container(keyedBy: DateEncodingKeys.self) - try container.encode("Date", forKey: .type) - let dateString = dateFormatter.string(from: date) - try container.encode(dateString, forKey: .iso) -}) - -let dateEncodingStrategy: JSONEncoder.DateEncodingStrategy = .custom({ (date, enc) in - var container = enc.container(keyedBy: DateEncodingKeys.self) - try container.encode("Date", forKey: .type) - let dateString = dateFormatter.string(from: date) - try container.encode(dateString, forKey: .iso) -}) - -internal extension Date { - func parseFormatted() -> String { - return dateFormatter.string(from: self) - } - var parseRepresentation: [String: String] { - return ["__type": "Date", "iso": parseFormatted()] - } -} - -let dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .custom({ (dec) -> Date in - do { - let container = try dec.singleValueContainer() - let decodedString = try container.decode(String.self) - return dateFormatter.date(from: decodedString)! - } catch let error { - let container = try dec.container(keyedBy: DateEncodingKeys.self) - if let decoded = try container.decodeIfPresent(String.self, forKey: .iso) { - return dateFormatter.date(from: decoded)! - } - } - throw ParseError(code: .unknownError, message: "unable to decode") -}) - -func getJSONEncoder() -> JSONEncoder { - let encoder = JSONEncoder() - encoder.dateEncodingStrategy = dateEncodingStrategy - return encoder -} - -private let forbiddenKeys = ["createdAt", "updatedAt", "objectId", "className"] - -func getParseEncoder() -> ParseEncoder { - return getParseEncoder(skipKeys: true) -} - -func getParseEncoderWithoutSkippingKeys() -> ParseEncoder { - return getParseEncoder(skipKeys: false) -} - -internal func getParseEncoder(skipKeys: Bool) -> ParseEncoder { - let encoder = ParseEncoder() - encoder.dateEncodingStrategy = parseDateEncodingStrategy - encoder.shouldEncodeKey = { (key, path) -> Bool in - if path.count == 0 // top level - && forbiddenKeys.firstIndex(of: key) != nil - && skipKeys { - return false - } - return true - } - return encoder -} - -extension JSONEncoder { - func encodeAsString(_ value: T) throws -> String where T: Encodable { - guard let string = String(data: try encode(value), encoding: .utf8) else { - throw ParseError(code: .unknownError, message: "Unable to encode object...") - } - return string - } -} - -func getDecoder() -> JSONDecoder { - let encoder = JSONDecoder() - encoder.dateDecodingStrategy = dateDecodingStrategy - return encoder -} - -public extension ObjectType { - func save(options: API.Options) throws -> Self { - return try saveCommand().execute(options: options) - } - - func save(options: API.Options, callbackQueue: DispatchQueue = .main, - completion: @escaping (Result) -> Void) { - saveCommand().executeAsync(options: options, callbackQueue: callbackQueue, completion: completion) - } - - func fetch(options: API.Options) throws -> Self { - return try fetchCommand().execute(options: options) - } - - func fetch(options: API.Options, callbackQueue: DispatchQueue = .main, - completion: @escaping (Result) -> Void) { - do { - try fetchCommand().executeAsync(options: options, callbackQueue: callbackQueue, completion: completion) - } catch let error as ParseError { - completion(.failure(error)) - } catch { - completion(.failure(ParseError(code: .unknownError, message: error.localizedDescription))) - } - } - - internal func saveCommand() -> API.Command { - return API.Command.saveCommand(self) - } - - internal func fetchCommand() throws -> API.Command { - return try API.Command.fetchCommand(self) - } -} - -extension ObjectType { - var endpoint: API.Endpoint { - if let objectId = objectId { - return .object(className: className, objectId: objectId) - } - return .objects(className: className) - } - - var isSaved: Bool { - return objectId != nil - } -} - -internal struct FindResult: Codable where T: ObjectType { - let results: [T] - let count: Int? -} - -public extension ObjectType { - var mutationContainer: ParseMutationContainer { - return ParseMutationContainer(target: self) - } -} diff --git a/Sources/ParseSwift/Objects Protocols/UserType.swift b/Sources/ParseSwift/Objects Protocols/UserType.swift deleted file mode 100644 index 4e13bec36..000000000 --- a/Sources/ParseSwift/Objects Protocols/UserType.swift +++ /dev/null @@ -1,150 +0,0 @@ -// -// ParseUserType.swift -// ParseSwift -// -// Created by Florent Vilmart. -// Copyright © 2020 Parse Community. All rights reserved. -// - -import Foundation - -internal struct CurrentUserInfo { - static var currentUser: Any? - static var currentSessionToken: String? -} - -public protocol UserType: ObjectType { - var username: String? { get set } - var email: String? { get set } - var password: String? { get set } -} - -public extension UserType { - var sessionToken: String? { - if let currentUser = CurrentUserInfo.currentUser as? Self, - currentUser.objectId != nil && self.objectId != nil && - currentUser.objectId == self.objectId { - return CurrentUserInfo.currentSessionToken - } - return nil - } - - static var className: String { - return "_User" - } -} - -public extension UserType { - static var current: Self? { - return CurrentUserInfo.currentUser as? Self - } - - static func login(username: String, - password: String) throws -> Self { - return try loginCommand(username: username, password: password) - .execute(options: []) - } - - static func login(username: String, password: String, callbackQueue: DispatchQueue = .main, - completion: @escaping (Result) -> Void) { - return loginCommand(username: username, password: password) - .executeAsync(options: [], callbackQueue: callbackQueue, completion: completion) - } - - static func signup(username: String, - password: String) throws -> Self { - return try signupCommand(username: username, password: password) - .execute(options: []) - } - - static func signup(username: String, password: String, callbackQueue: DispatchQueue = .main, - completion: @escaping (Result) -> Void) { - return signupCommand(username: username, password: password) - .executeAsync(options: [], callbackQueue: callbackQueue, completion: completion) - } - - static func logout() throws { - _ = try logoutCommand() - .execute(options: []) - } - - static func logout(callbackQueue: DispatchQueue = .main, completion: @escaping (Result) -> Void) { - logoutCommand() - .executeAsync(options: [], callbackQueue: callbackQueue) { result in - completion(result.map { true }) - } - } - - func signup() throws -> Self { - return try signupCommand() - .execute(options: []) - } -} - -private extension UserType { - private static func loginCommand(username: String, - password: String) -> API.Command { - let params = [ - "username": username, - "password": password - ] - return API.Command(method: .GET, - path: .login, - params: params) { (data) -> Self in - let user = try getDecoder().decode(Self.self, from: data) - let response = try getDecoder().decode(LoginSignupResponse.self, from: data) - CurrentUserInfo.currentUser = user - CurrentUserInfo.currentSessionToken = response.sessionToken - return user - } - } - - private static func signupCommand(username: String, - password: String) -> API.Command { - let body = SignupBody(username: username, password: password) - return API.Command(method: .POST, path: .signup, body: body) { (data) -> Self in - let response = try getDecoder().decode(LoginSignupResponse.self, from: data) - var user = try getDecoder().decode(Self.self, from: data) - user.username = username - user.password = password - user.updatedAt = response.updatedAt ?? response.createdAt - - // Set the current user - CurrentUserInfo.currentUser = user - CurrentUserInfo.currentSessionToken = response.sessionToken - return user - } - } - - private func signupCommand() -> API.Command { - var user = self - return API.Command(method: .POST, path: .signup, body: user) { (data) -> Self in - let response = try getDecoder().decode(LoginSignupResponse.self, from: data) - user.updatedAt = response.updatedAt ?? response.createdAt - user.createdAt = response.createdAt - // Set the current user - CurrentUserInfo.currentUser = user - CurrentUserInfo.currentSessionToken = response.sessionToken - return user - } - } - - private static func logoutCommand() -> API.Command { - return API.Command(method: .POST, path: .logout) { (_) -> Void in - CurrentUserInfo.currentUser = nil - CurrentUserInfo.currentSessionToken = nil - } - } -} - -public struct SignupBody: Codable { - let username: String - let password: String -} - -private struct LoginSignupResponse: Codable { - let createdAt: Date - let objectId: String - let sessionToken: String - var updatedAt: Date? -} diff --git a/Sources/ParseSwift/Objects/ParseObject.swift b/Sources/ParseSwift/Objects/ParseObject.swift index 85d894189..bc20c454e 100644 --- a/Sources/ParseSwift/Objects/ParseObject.swift +++ b/Sources/ParseSwift/Objects/ParseObject.swift @@ -35,19 +35,24 @@ extension ParseObject { } // MARK: Batch Support -public extension ParseObject { - static func saveAll(_ objects: Self...) throws -> [(Self, ParseError?)] { - return try objects.saveAll() - } -} - -extension Sequence where Element: ParseObject { - public func saveAll(options: API.Options = []) throws -> [(Self.Element, ParseError?)] { +public extension Sequence where Element: ParseObject { + func saveAll(options: API.Options = []) throws -> [(Result)] { let commands = map { $0.saveCommand() } return try API.Command .batch(commands: commands) .execute(options: options) } + + func saveAll( + options: API.Options = [], + callbackQueue: DispatchQueue = .main, + completion: @escaping (Result<[(Result)], ParseError>) -> Void + ) { + let commands = map { $0.saveCommand() } + API.Command + .batch(commands: commands) + .executeAsync(options: options, callbackQueue: callbackQueue, completion: completion) + } } // MARK: Convenience @@ -83,6 +88,20 @@ extension ParseObject { return try fetchCommand().execute(options: options) } + public func fetch( + options: API.Options, + callbackQueue: DispatchQueue = .main, + completion: @escaping (Result) -> Void + ) { + do { + try fetchCommand().executeAsync(options: options, callbackQueue: callbackQueue, completion: completion) + } catch let error as ParseError { + completion(.failure(error)) + } catch { + completion(.failure(ParseError(code: .unknownError, message: error.localizedDescription))) + } + } + internal func fetchCommand() throws -> API.Command { return try API.Command.fetchCommand(self) } @@ -116,6 +135,14 @@ extension ParseObject { return try saveCommand().execute(options: options) } + func save( + options: API.Options, + callbackQueue: DispatchQueue = .main, + completion: @escaping (Result) -> Void + ) { + saveCommand().executeAsync(options: options, callbackQueue: callbackQueue, completion: completion) + } + internal func saveCommand() -> API.Command { return API.Command.saveCommand(self) } diff --git a/Sources/ParseSwift/Objects/ParseUser.swift b/Sources/ParseSwift/Objects/ParseUser.swift index 692f4e584..d4e01ff43 100644 --- a/Sources/ParseSwift/Objects/ParseUser.swift +++ b/Sources/ParseSwift/Objects/ParseUser.swift @@ -44,6 +44,16 @@ extension ParseUser { return try loginCommand(username: username, password: password).execute(options: []) } + public static func login( + username: String, + password: String, + callbackQueue: DispatchQueue = .main, + completion: @escaping (Result) -> Void + ) { + return loginCommand(username: username, password: password) + .executeAsync(options: [], callbackQueue: callbackQueue, completion: completion) + } + private static func loginCommand(username: String, password: String) -> API.Command { let params = [ @@ -73,6 +83,12 @@ extension ParseUser { _ = try logoutCommand().execute(options: []) } + static func logout(callbackQueue: DispatchQueue = .main, completion: @escaping (Result) -> Void) { + logoutCommand().executeAsync(options: [], callbackQueue: callbackQueue) { result in + completion(result.map { true }) + } + } + private static func logoutCommand() -> API.Command { return API.Command(method: .POST, path: .logout) { (_) -> Void in currentUserContainer = nil @@ -91,6 +107,16 @@ extension ParseUser { return try signupCommand().execute(options: []) } + public static func signup( + username: String, + password: String, + callbackQueue: DispatchQueue = .main, + completion: @escaping (Result) -> Void + ) { + return signupCommand(username: username, password: password) + .executeAsync(options: [], callbackQueue: callbackQueue, completion: completion) + } + private static func signupCommand(username: String, password: String) -> API.Command { diff --git a/Sources/ParseSwift/Parse Types/FindResult.swift b/Sources/ParseSwift/Parse Types/FindResult.swift new file mode 100644 index 000000000..e7e0e87fc --- /dev/null +++ b/Sources/ParseSwift/Parse Types/FindResult.swift @@ -0,0 +1,12 @@ +// +// FindResult.swift +// ParseSwift +// +// Created by Pranjal Satija on 8/4/20. +// Copyright © 2020 Parse Community. All rights reserved. +// + +internal struct FindResult: Codable where T: ParseObject { + let results: [T] + let count: Int? +} diff --git a/Sources/ParseSwift/Parse Types/Query.swift b/Sources/ParseSwift/Parse Types/Query.swift index 379d3d3c2..3008eddea 100644 --- a/Sources/ParseSwift/Parse Types/Query.swift +++ b/Sources/ParseSwift/Parse Types/Query.swift @@ -93,7 +93,7 @@ public func == (key: String, value: T) -> QueryConstraint where T: Encodable return QueryConstraint(key: key, value: value, comparator: .equals) } -private struct InQuery: Encodable where T: ObjectType { +private struct InQuery: Encodable where T: ParseObject { let query: Query var className: String { return T.className @@ -136,7 +136,7 @@ internal struct QueryWhere: Encodable { } } -public struct Query: Encodable where T: ObjectType { +public struct Query: Encodable where T: ParseObject { // interpolate as GET private let method: String = "GET" private var limit: Int = 100 @@ -256,7 +256,7 @@ extension Query: Querying { private extension Query { private func findCommand() -> API.Command, [ResultType]> { return API.Command(method: .POST, path: endpoint, body: self) { - try getDecoder().decode(FindResult.self, from: $0).results + try ParseCoding.jsonDecoder().decode(FindResult.self, from: $0).results } } @@ -264,7 +264,7 @@ private extension Query { var query = self query.limit = 1 return API.Command(method: .POST, path: endpoint, body: query) { - try getDecoder().decode(FindResult.self, from: $0).results.first + try ParseCoding.jsonDecoder().decode(FindResult.self, from: $0).results.first } } @@ -273,7 +273,7 @@ private extension Query { query.limit = 1 query.isCount = true return API.Command(method: .POST, path: endpoint, body: query) { - try getDecoder().decode(FindResult.self, from: $0).count ?? 0 + try ParseCoding.jsonDecoder().decode(FindResult.self, from: $0).count ?? 0 } } } diff --git a/Tests/ParseSwiftTests/ParseObjectBatchTests.swift b/Tests/ParseSwiftTests/ParseObjectBatchTests.swift index d3e365d17..5946204ff 100755 --- a/Tests/ParseSwiftTests/ParseObjectBatchTests.swift +++ b/Tests/ParseSwiftTests/ParseObjectBatchTests.swift @@ -12,7 +12,7 @@ import XCTest class ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_length - struct GameScore: ParseSwift.ObjectType { + struct GameScore: ParseSwift.ParseObject { //: Those are required for Object var objectId: String? var createdAt: Date? @@ -65,11 +65,11 @@ class ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_le BatchResponseItem(success: scoreOnServer2, error: nil)] let encoded: Data! do { - encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(response) + encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(response) //Get dates in correct format from ParseDecoding strategy - let encoded1 = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(scoreOnServer) + let encoded1 = try scoreOnServer.getEncoder(skipKeys: false).encode(scoreOnServer) scoreOnServer = try scoreOnServer.getTestDecoder().decode(GameScore.self, from: encoded1) - let encoded2 = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(scoreOnServer2) + let encoded2 = try scoreOnServer.getEncoder(skipKeys: false).encode(scoreOnServer2) scoreOnServer2 = try scoreOnServer.getTestDecoder().decode(GameScore.self, from: encoded2) } catch { @@ -87,7 +87,7 @@ class ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_le switch saved[0] { case .success(let first): - XCTAssertEqual(first, scoreOnServer) + XCTAssert(first.hasSameObjectId(as: scoreOnServer)) guard let savedCreatedAt = first.createdAt, let savedUpdatedAt = first.updatedAt else { XCTFail("Should unwrap dates") @@ -108,7 +108,7 @@ class ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_le switch saved[1] { case .success(let second): - XCTAssertEqual(second, scoreOnServer2) + XCTAssert(second.hasSameObjectId(as: scoreOnServer2)) guard let savedCreatedAt = second.createdAt, let savedUpdatedAt = second.updatedAt else { XCTFail("Should unwrap dates") @@ -136,7 +136,7 @@ class ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_le switch saved[0] { case .success(let first): - XCTAssertEqual(first, scoreOnServer) + XCTAssert(first.hasSameObjectId(as: scoreOnServer)) guard let savedCreatedAt = first.createdAt, let savedUpdatedAt = first.updatedAt else { XCTFail("Should unwrap dates") @@ -157,7 +157,7 @@ class ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_le switch saved[1] { case .success(let second): - XCTAssertEqual(second, scoreOnServer2) + XCTAssert(second.hasSameObjectId(as: scoreOnServer2)) guard let savedCreatedAt = second.createdAt, let savedUpdatedAt = second.updatedAt else { XCTFail("Should unwrap dates") @@ -197,7 +197,7 @@ class ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_le MockURLProtocol.mockRequests { _ in do { - let encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode([scoreOnServer, scoreOnServer2]) + let encoded = try scoreOnServer.getEncoder(skipKeys: false).encode([scoreOnServer, scoreOnServer2]) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil @@ -249,11 +249,11 @@ class ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_le BatchResponseItem(success: scoreOnServer2, error: nil)] let encoded: Data! do { - encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(response) + encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(response) //Get dates in correct format from ParseDecoding strategy - let encoded1 = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(scoreOnServer) + let encoded1 = try scoreOnServer.getEncoder(skipKeys: false).encode(scoreOnServer) scoreOnServer = try scoreOnServer.getTestDecoder().decode(GameScore.self, from: encoded1) - let encoded2 = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(scoreOnServer2) + let encoded2 = try scoreOnServer.getEncoder(skipKeys: false).encode(scoreOnServer2) scoreOnServer2 = try scoreOnServer.getTestDecoder().decode(GameScore.self, from: encoded2) } catch { @@ -391,7 +391,7 @@ class ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_le MockURLProtocol.mockRequests { _ in do { - let encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode([scoreOnServer, scoreOnServer2]) + let encoded = try scoreOnServer.getEncoder(skipKeys: false).encode([scoreOnServer, scoreOnServer2]) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil @@ -441,11 +441,11 @@ class ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_le let encoded: Data! do { - encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(response) + encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(response) //Get dates in correct format from ParseDecoding strategy - let encoded1 = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(scoreOnServer) + let encoded1 = try scoreOnServer.getEncoder(skipKeys: false).encode(scoreOnServer) scoreOnServer = try scoreOnServer.getTestDecoder().decode(GameScore.self, from: encoded1) - let encoded2 = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(scoreOnServer2) + let encoded2 = try scoreOnServer.getEncoder(skipKeys: false).encode(scoreOnServer2) scoreOnServer2 = try scoreOnServer.getTestDecoder().decode(GameScore.self, from: encoded2) } catch { @@ -463,7 +463,7 @@ class ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_le switch saved[0] { case .success(let first): - XCTAssertEqual(first, scoreOnServer) + XCTAssert(first.hasSameObjectId(as: scoreOnServer)) guard let savedCreatedAt = first.createdAt, let savedUpdatedAt = first.updatedAt else { XCTFail("Should unwrap dates") @@ -558,7 +558,7 @@ class ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_le switch firstObject { case .success(let first): - XCTAssertEqual(first, scoreOnServer) + XCTAssert(first.hasSameObjectId(as: scoreOnServer)) guard let savedCreatedAt = first.createdAt, let savedUpdatedAt = first.updatedAt else { XCTFail("Should unwrap dates") @@ -580,7 +580,7 @@ class ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_le switch secondObject { case .success(let second): - XCTAssertEqual(second, scoreOnServer2) + XCTAssert(second.hasSameObjectId(as: scoreOnServer2)) guard let savedCreatedAt = second.createdAt, let savedUpdatedAt = second.updatedAt else { XCTFail("Should unwrap dates") @@ -688,11 +688,11 @@ class ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_le BatchResponseItem(success: scoreOnServer2, error: nil)] let encoded: Data! do { - encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(response) + encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(response) //Get dates in correct format from ParseDecoding strategy - let encoded1 = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(scoreOnServer) + let encoded1 = try scoreOnServer.getEncoder(skipKeys: false).encode(scoreOnServer) scoreOnServer = try scoreOnServer.getTestDecoder().decode(GameScore.self, from: encoded1) - let encoded2 = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(scoreOnServer2) + let encoded2 = try scoreOnServer.getEncoder(skipKeys: false).encode(scoreOnServer2) scoreOnServer2 = try scoreOnServer.getTestDecoder().decode(GameScore.self, from: encoded2) } catch { @@ -729,11 +729,11 @@ class ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_le BatchResponseItem(success: scoreOnServer2, error: nil)] let encoded: Data! do { - encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(response) + encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(response) //Get dates in correct format from ParseDecoding strategy - let encoded1 = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(scoreOnServer) + let encoded1 = try scoreOnServer.getEncoder(skipKeys: false).encode(scoreOnServer) scoreOnServer = try scoreOnServer.getTestDecoder().decode(GameScore.self, from: encoded1) - let encoded2 = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(scoreOnServer2) + let encoded2 = try scoreOnServer.getEncoder(skipKeys: false).encode(scoreOnServer2) scoreOnServer2 = try scoreOnServer.getTestDecoder().decode(GameScore.self, from: encoded2) } catch { @@ -901,11 +901,11 @@ class ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_le let encoded: Data! do { - encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(response) + encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(response) //Get dates in correct format from ParseDecoding strategy - let encoded1 = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(scoreOnServer) + let encoded1 = try scoreOnServer.getEncoder(skipKeys: false).encode(scoreOnServer) scoreOnServer = try scoreOnServer.getTestDecoder().decode(GameScore.self, from: encoded1) - let encoded2 = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(scoreOnServer2) + let encoded2 = try scoreOnServer.getEncoder(skipKeys: false).encode(scoreOnServer2) scoreOnServer2 = try scoreOnServer.getTestDecoder().decode(GameScore.self, from: encoded2) } catch { @@ -944,11 +944,11 @@ class ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_le let encoded: Data! do { - encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(response) + encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(response) //Get dates in correct format from ParseDecoding strategy - let encoded1 = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(scoreOnServer) + let encoded1 = try scoreOnServer.getEncoder(skipKeys: false).encode(scoreOnServer) scoreOnServer = try scoreOnServer.getTestDecoder().decode(GameScore.self, from: encoded1) - let encoded2 = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(scoreOnServer2) + let encoded2 = try scoreOnServer.getEncoder(skipKeys: false).encode(scoreOnServer2) scoreOnServer2 = try scoreOnServer.getTestDecoder().decode(GameScore.self, from: encoded2) } catch { diff --git a/Tests/ParseSwiftTests/ParseObjectCommandTests.swift b/Tests/ParseSwiftTests/ParseObjectCommandTests.swift index 18afe0ea1..61bcb9872 100644 --- a/Tests/ParseSwiftTests/ParseObjectCommandTests.swift +++ b/Tests/ParseSwiftTests/ParseObjectCommandTests.swift @@ -12,7 +12,7 @@ import XCTest class ParseObjectCommandTests: XCTestCase { // swiftlint:disable:this type_body_length - struct GameScore: ParseSwift.ObjectType { + struct GameScore: ParseSwift.ParseObject { //: Those are required for Object var objectId: String? var createdAt: Date? @@ -74,7 +74,7 @@ class ParseObjectCommandTests: XCTestCase { // swiftlint:disable:this type_body_ scoreOnServer.ACL = nil let encoded: Data! do { - encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(scoreOnServer) + encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(scoreOnServer) //Get dates in correct format from ParseDecoding strategy scoreOnServer = try scoreOnServer.getTestDecoder().decode(GameScore.self, from: encoded) } catch { @@ -87,7 +87,7 @@ class ParseObjectCommandTests: XCTestCase { // swiftlint:disable:this type_body_ } do { let fetched = try score.fetch(options: []) - XCTAssertEqual(fetched, scoreOnServer) + XCTAssert(fetched.hasSameObjectId(as: scoreOnServer)) guard let fetchedCreatedAt = fetched.createdAt, let fetchedUpdatedAt = fetched.updatedAt else { XCTFail("Should unwrap dates") @@ -107,7 +107,7 @@ class ParseObjectCommandTests: XCTestCase { // swiftlint:disable:this type_body_ do { let fetched = try score.fetch(options: [.useMasterKey]) - XCTAssertEqual(fetched, scoreOnServer) + XCTAssert(fetched.hasSameObjectId(as: scoreOnServer)) guard let fetchedCreatedAt = fetched.createdAt, let fetchedUpdatedAt = fetched.updatedAt else { XCTFail("Should unwrap dates") @@ -134,7 +134,7 @@ class ParseObjectCommandTests: XCTestCase { // swiftlint:disable:this type_body_ switch result { case .success(let fetched): - XCTAssertEqual(fetched, scoreOnServer) + XCTAssert(fetched.hasSameObjectId(as: scoreOnServer)) guard let fetchedCreatedAt = fetched.createdAt, let fetchedUpdatedAt = fetched.updatedAt else { XCTFail("Should unwrap dates") @@ -159,7 +159,7 @@ class ParseObjectCommandTests: XCTestCase { // swiftlint:disable:this type_body_ expectation2.fulfill() switch result { case .success(let fetched): - XCTAssertEqual(fetched, scoreOnServer) + XCTAssert(fetched.hasSameObjectId(as: scoreOnServer)) guard let fetchedCreatedAt = fetched.createdAt, let fetchedUpdatedAt = fetched.updatedAt else { XCTFail("Should unwrap dates") @@ -192,7 +192,7 @@ class ParseObjectCommandTests: XCTestCase { // swiftlint:disable:this type_body_ let encoded: Data! do { - encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(scoreOnServer) + encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(scoreOnServer) //Get dates in correct format from ParseDecoding strategy scoreOnServer = try scoreOnServer.getTestDecoder().decode(GameScore.self, from: encoded) } catch { @@ -220,7 +220,7 @@ class ParseObjectCommandTests: XCTestCase { // swiftlint:disable:this type_body_ scoreOnServer.ACL = nil let encoded: Data! do { - encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(scoreOnServer) + encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(scoreOnServer) //Get dates in correct format from ParseDecoding strategy scoreOnServer = try scoreOnServer.getTestDecoder().decode(GameScore.self, from: encoded) } catch { @@ -273,7 +273,7 @@ class ParseObjectCommandTests: XCTestCase { // swiftlint:disable:this type_body_ let encoded: Data! do { - encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(scoreOnServer) + encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(scoreOnServer) //Get dates in correct format from ParseDecoding strategy scoreOnServer = try scoreOnServer.getTestDecoder().decode(GameScore.self, from: encoded) } catch { @@ -286,7 +286,7 @@ class ParseObjectCommandTests: XCTestCase { // swiftlint:disable:this type_body_ } do { let saved = try score.save() - XCTAssertEqual(saved, scoreOnServer) + XCTAssert(saved.hasSameObjectId(as: scoreOnServer)) guard let savedCreatedAt = saved.createdAt, let savedUpdatedAt = saved.updatedAt else { XCTFail("Should unwrap dates") @@ -306,7 +306,7 @@ class ParseObjectCommandTests: XCTestCase { // swiftlint:disable:this type_body_ do { let saved = try score.save(options: [.useMasterKey]) - XCTAssertEqual(saved, scoreOnServer) + XCTAssert(saved.hasSameObjectId(as: scoreOnServer)) guard let savedCreatedAt = saved.createdAt, let savedUpdatedAt = saved.updatedAt else { XCTFail("Should unwrap dates") @@ -337,7 +337,7 @@ class ParseObjectCommandTests: XCTestCase { // swiftlint:disable:this type_body_ let encoded: Data! do { - encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(scoreOnServer) + encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(scoreOnServer) //Get dates in correct format from ParseDecoding strategy scoreOnServer = try scoreOnServer.getTestDecoder().decode(GameScore.self, from: encoded) } catch { @@ -397,7 +397,7 @@ class ParseObjectCommandTests: XCTestCase { // swiftlint:disable:this type_body_ switch result { case .success(let saved): - XCTAssertEqual(saved, scoreOnServer) + XCTAssert(saved.hasSameObjectId(as: scoreOnServer)) guard let savedCreatedAt = saved.createdAt, let savedUpdatedAt = saved.updatedAt else { XCTFail("Should unwrap dates") @@ -424,7 +424,7 @@ class ParseObjectCommandTests: XCTestCase { // swiftlint:disable:this type_body_ switch result { case .success(let saved): - XCTAssertEqual(saved, scoreOnServer) + XCTAssert(saved.hasSameObjectId(as: scoreOnServer)) guard let savedCreatedAt = saved.createdAt, let savedUpdatedAt = saved.updatedAt else { XCTFail("Should unwrap dates") @@ -455,7 +455,7 @@ class ParseObjectCommandTests: XCTestCase { // swiftlint:disable:this type_body_ scoreOnServer.ACL = nil let encoded: Data! do { - encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(scoreOnServer) + encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(scoreOnServer) //Get dates in correct format from ParseDecoding strategy scoreOnServer = try scoreOnServer.getTestDecoder().decode(GameScore.self, from: encoded) } catch { @@ -481,7 +481,7 @@ class ParseObjectCommandTests: XCTestCase { // swiftlint:disable:this type_body_ scoreOnServer.ACL = nil let encoded: Data! do { - encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(scoreOnServer) + encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(scoreOnServer) //Get dates in correct format from ParseDecoding strategy scoreOnServer = try scoreOnServer.getTestDecoder().decode(GameScore.self, from: encoded) } catch { @@ -562,7 +562,7 @@ class ParseObjectCommandTests: XCTestCase { // swiftlint:disable:this type_body_ scoreOnServer.updatedAt = Date() let encoded: Data! do { - encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(scoreOnServer) + encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(scoreOnServer) //Get dates in correct format from ParseDecoding strategy scoreOnServer = try scoreOnServer.getTestDecoder().decode(GameScore.self, from: encoded) } catch { @@ -589,7 +589,7 @@ class ParseObjectCommandTests: XCTestCase { // swiftlint:disable:this type_body_ scoreOnServer.updatedAt = Date() let encoded: Data! do { - encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(scoreOnServer) + encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(scoreOnServer) //Get dates in correct format from ParseDecoding strategy scoreOnServer = try scoreOnServer.getTestDecoder().decode(GameScore.self, from: encoded) } catch { diff --git a/Tests/ParseSwiftTests/ParseQueryTests.swift b/Tests/ParseSwiftTests/ParseQueryTests.swift index ab4f8ac87..18f782d51 100755 --- a/Tests/ParseSwiftTests/ParseQueryTests.swift +++ b/Tests/ParseSwiftTests/ParseQueryTests.swift @@ -12,7 +12,7 @@ import XCTest class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length - struct GameScore: ParseSwift.ObjectType { + struct GameScore: ParseSwift.ParseObject { //: Those are required for Object var objectId: String? var createdAt: Date? @@ -64,7 +64,7 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length let results = FindResult(results: [scoreOnServer], count: 1) MockURLProtocol.mockRequests { _ in do { - let encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(results) + let encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(results) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil @@ -78,7 +78,7 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length XCTFail("Should unwrap first object found") return } - XCTAssertEqual(score, scoreOnServer) + XCTAssert(score.hasSameObjectId(as: scoreOnServer)) } catch { XCTFail(error.localizedDescription) } @@ -98,7 +98,7 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length XCTFail("Should unwrap score count") return } - XCTAssertEqual(score, scoreOnServer) + XCTAssert(score.hasSameObjectId(as: scoreOnServer)) case .failure(let error): XCTFail(error.localizedDescription) } @@ -117,7 +117,7 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length let results = FindResult(results: [scoreOnServer], count: 1) MockURLProtocol.mockRequests { _ in do { - let encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(results) + let encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(results) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil @@ -139,7 +139,7 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length let results = FindResult(results: [scoreOnServer], count: 1) MockURLProtocol.mockRequests { _ in do { - let encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(results) + let encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(results) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil @@ -158,7 +158,7 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length let results = FindResult(results: [scoreOnServer], count: 1) MockURLProtocol.mockRequests { _ in do { - let encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(results) + let encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(results) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil @@ -172,7 +172,7 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length XCTFail("Should unwrap first object found") return } - XCTAssertEqual(score, scoreOnServer) + XCTAssert(score.hasSameObjectId(as: scoreOnServer)) } catch { XCTFail(error.localizedDescription) } @@ -188,7 +188,7 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length switch result { case .success(let score): - XCTAssertEqual(score, scoreOnServer) + XCTAssert(score.hasSameObjectId(as: scoreOnServer)) case .failure(let error): XCTFail(error.localizedDescription) @@ -207,7 +207,7 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length let results = FindResult(results: [scoreOnServer], count: 1) MockURLProtocol.mockRequests { _ in do { - let encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(results) + let encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(results) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil @@ -229,7 +229,7 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length let results = FindResult(results: [scoreOnServer], count: 1) MockURLProtocol.mockRequests { _ in do { - let encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(results) + let encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(results) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil @@ -248,7 +248,7 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length let results = FindResult(results: [scoreOnServer], count: 1) MockURLProtocol.mockRequests { _ in do { - let encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(results) + let encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(results) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil @@ -294,7 +294,7 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length let results = FindResult(results: [scoreOnServer], count: 1) MockURLProtocol.mockRequests { _ in do { - let encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(results) + let encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(results) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil @@ -316,7 +316,7 @@ class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length let results = FindResult(results: [scoreOnServer], count: 1) MockURLProtocol.mockRequests { _ in do { - let encoded = try scoreOnServer.getEncoderWithoutSkippingKeys().encode(results) + let encoded = try scoreOnServer.getEncoder(skipKeys: false).encode(results) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil diff --git a/Tests/ParseSwiftTests/ParseUserCommandTests.swift b/Tests/ParseSwiftTests/ParseUserCommandTests.swift index 42e5aafd7..5f763def8 100644 --- a/Tests/ParseSwiftTests/ParseUserCommandTests.swift +++ b/Tests/ParseSwiftTests/ParseUserCommandTests.swift @@ -12,7 +12,7 @@ import XCTest class ParseUserCommandTests: XCTestCase { // swiftlint:disable:this type_body_length - struct User: ParseSwift.UserType { + struct User: ParseSwift.ParseUser { //: Those are required for Object var objectId: String? var createdAt: Date? @@ -28,7 +28,7 @@ class ParseUserCommandTests: XCTestCase { // swiftlint:disable:this type_body_le var customKey: String? } - struct LoginSignupResponse: ParseSwift.UserType { + struct LoginSignupResponse: ParseSwift.ParseUser { var objectId: String? var createdAt: Date? var sessionToken: String @@ -102,7 +102,7 @@ class ParseUserCommandTests: XCTestCase { // swiftlint:disable:this type_body_le userOnServer.ACL = nil let encoded: Data! do { - encoded = try userOnServer.getEncoderWithoutSkippingKeys().encode(userOnServer) + encoded = try userOnServer.getEncoder(skipKeys: false).encode(userOnServer) //Get dates in correct format from ParseDecoding strategy userOnServer = try userOnServer.getTestDecoder().decode(User.self, from: encoded) } catch { @@ -115,7 +115,7 @@ class ParseUserCommandTests: XCTestCase { // swiftlint:disable:this type_body_le do { let fetched = try user.fetch() - XCTAssertEqual(fetched, userOnServer) + XCTAssert(fetched.hasSameObjectId(as: userOnServer)) guard let fetchedCreatedAt = fetched.createdAt, let fetchedUpdatedAt = fetched.updatedAt else { XCTFail("Should unwrap dates") @@ -135,7 +135,7 @@ class ParseUserCommandTests: XCTestCase { // swiftlint:disable:this type_body_le do { let fetched = try user.fetch(options: [.useMasterKey]) - XCTAssertEqual(fetched, userOnServer) + XCTAssert(fetched.hasSameObjectId(as: userOnServer)) guard let fetchedCreatedAt = fetched.createdAt, let fetchedUpdatedAt = fetched.updatedAt else { XCTFail("Should unwrap dates") @@ -164,7 +164,7 @@ class ParseUserCommandTests: XCTestCase { // swiftlint:disable:this type_body_le switch result { case .success(let fetched): - XCTAssertEqual(fetched, userOnServer) + XCTAssert(fetched.hasSameObjectId(as: userOnServer)) guard let fetchedCreatedAt = fetched.createdAt, let fetchedUpdatedAt = fetched.updatedAt else { XCTFail("Should unwrap dates") @@ -191,7 +191,7 @@ class ParseUserCommandTests: XCTestCase { // swiftlint:disable:this type_body_le switch result { case .success(let fetched): - XCTAssertEqual(fetched, userOnServer) + XCTAssert(fetched.hasSameObjectId(as: userOnServer)) guard let fetchedCreatedAt = fetched.createdAt, let fetchedUpdatedAt = fetched.updatedAt else { XCTFail("Should unwrap dates") @@ -223,7 +223,7 @@ class ParseUserCommandTests: XCTestCase { // swiftlint:disable:this type_body_le userOnServer.ACL = nil let encoded: Data! do { - encoded = try userOnServer.getEncoderWithoutSkippingKeys().encode(userOnServer) + encoded = try userOnServer.getEncoder(skipKeys: false).encode(userOnServer) //Get dates in correct format from ParseDecoding strategy userOnServer = try userOnServer.getTestDecoder().decode(User.self, from: encoded) } catch { @@ -280,7 +280,7 @@ class ParseUserCommandTests: XCTestCase { // swiftlint:disable:this type_body_le let encoded: Data! do { - encoded = try userOnServer.getEncoderWithoutSkippingKeys().encode(userOnServer) + encoded = try userOnServer.getEncoder(skipKeys: false).encode(userOnServer) //Get dates in correct format from ParseDecoding strategy userOnServer = try userOnServer.getTestDecoder().decode(User.self, from: encoded) } catch { @@ -397,7 +397,7 @@ class ParseUserCommandTests: XCTestCase { // swiftlint:disable:this type_body_le userOnServer.updatedAt = Date() let encoded: Data! do { - encoded = try userOnServer.getEncoderWithoutSkippingKeys().encode(userOnServer) + encoded = try userOnServer.getEncoder(skipKeys: false).encode(userOnServer) //Get dates in correct format from ParseDecoding strategy userOnServer = try userOnServer.getTestDecoder().decode(User.self, from: encoded) } catch { @@ -425,7 +425,7 @@ class ParseUserCommandTests: XCTestCase { // swiftlint:disable:this type_body_le userOnServer.updatedAt = Date() let encoded: Data! do { - encoded = try userOnServer.getEncoderWithoutSkippingKeys().encode(userOnServer) + encoded = try userOnServer.getEncoder(skipKeys: false).encode(userOnServer) //Get dates in correct format from ParseDecoding strategy userOnServer = try userOnServer.getTestDecoder().decode(User.self, from: encoded) } catch { @@ -444,7 +444,7 @@ class ParseUserCommandTests: XCTestCase { // swiftlint:disable:this type_body_le MockURLProtocol.mockRequests { _ in do { - let encoded = try loginResponse.getEncoderWithoutSkippingKeys().encode(loginResponse) + let encoded = try loginResponse.getEncoder(skipKeys: false).encode(loginResponse) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil @@ -500,7 +500,7 @@ class ParseUserCommandTests: XCTestCase { // swiftlint:disable:this type_body_le MockURLProtocol.mockRequests { _ in do { - let encoded = try loginResponse.getEncoderWithoutSkippingKeys().encode(loginResponse) + let encoded = try loginResponse.getEncoder(skipKeys: false).encode(loginResponse) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil @@ -517,7 +517,7 @@ class ParseUserCommandTests: XCTestCase { // swiftlint:disable:this type_body_le MockURLProtocol.mockRequests { _ in do { - let encoded = try loginResponse.getEncoderWithoutSkippingKeys().encode(loginResponse) + let encoded = try loginResponse.getEncoder(skipKeys: false).encode(loginResponse) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil @@ -532,7 +532,7 @@ class ParseUserCommandTests: XCTestCase { // swiftlint:disable:this type_body_le MockURLProtocol.mockRequests { _ in do { - let encoded = try loginResponse.getEncoderWithoutSkippingKeys().encode(loginResponse) + let encoded = try loginResponse.getEncoder(skipKeys: false).encode(loginResponse) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil @@ -588,7 +588,7 @@ class ParseUserCommandTests: XCTestCase { // swiftlint:disable:this type_body_le MockURLProtocol.mockRequests { _ in do { - let encoded = try loginResponse.getEncoderWithoutSkippingKeys().encode(loginResponse) + let encoded = try loginResponse.getEncoder(skipKeys: false).encode(loginResponse) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil @@ -605,7 +605,7 @@ class ParseUserCommandTests: XCTestCase { // swiftlint:disable:this type_body_le MockURLProtocol.mockRequests { _ in do { - let encoded = try loginResponse.getEncoderWithoutSkippingKeys().encode(loginResponse) + let encoded = try loginResponse.getEncoder(skipKeys: false).encode(loginResponse) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil @@ -620,7 +620,7 @@ class ParseUserCommandTests: XCTestCase { // swiftlint:disable:this type_body_le MockURLProtocol.mockRequests { _ in do { - let encoded = try loginResponse.getEncoderWithoutSkippingKeys().encode(loginResponse) + let encoded = try loginResponse.getEncoder(skipKeys: false).encode(loginResponse) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil @@ -655,7 +655,7 @@ class ParseUserCommandTests: XCTestCase { // swiftlint:disable:this type_body_le MockURLProtocol.mockRequests { _ in do { - let encoded = try loginResponse.getEncoderWithoutSkippingKeys().encode(loginResponse) + let encoded = try loginResponse.getEncoder(skipKeys: false).encode(loginResponse) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil @@ -672,7 +672,7 @@ class ParseUserCommandTests: XCTestCase { // swiftlint:disable:this type_body_le MockURLProtocol.mockRequests { _ in do { - let encoded = try loginResponse.getEncoderWithoutSkippingKeys().encode(loginResponse) + let encoded = try loginResponse.getEncoder(skipKeys: false).encode(loginResponse) return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0) } catch { return nil From 55f0d7d4794e940e32942e4eaf4f1dd0e9e5df38 Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Tue, 4 Aug 2020 12:28:05 -0500 Subject: [PATCH 23/30] add array support to ParseEncoder; replace _ with --- Sources/ParseSwift/Coding/ParseEncoder.swift | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Sources/ParseSwift/Coding/ParseEncoder.swift b/Sources/ParseSwift/Coding/ParseEncoder.swift index c5324156d..8c63e3b71 100644 --- a/Sources/ParseSwift/Coding/ParseEncoder.swift +++ b/Sources/ParseSwift/Coding/ParseEncoder.swift @@ -39,6 +39,11 @@ public struct ParseEncoder { let dictionary = try encodeToDictionary(value) return try jsonEncoder.encode(AnyCodable(dictionary, dateEncodingStrategy: dateEncodingStrategy!)) } + + func encode(_ array: [T]) throws -> Data { + let dictionaries = try array.map { try encodeToDictionary($0) } + return try jsonEncoder.encode(AnyCodable(dictionaries, dateEncodingStrategy: dateEncodingStrategy!)) + } } // MARK: _ParseEncoder @@ -170,7 +175,7 @@ internal struct _ParseEncoderSingleValueEncodingContainer: SingleValueEncodingCo } var key: String { - codingPath.last?.stringValue ?? "_" + codingPath.last?.stringValue ?? "" } mutating func encodeNil() throws { @@ -202,7 +207,7 @@ internal struct _ParseEncoderUnkeyedEncodingContainer: UnkeyedEncodingContainer } var key: String { - codingPath.last?.stringValue ?? "_" + codingPath.last?.stringValue ?? "" } init(codingPath: [CodingKey], dictionary: NSMutableDictionary, skippingKeys: Set) { From 81c2cbdf1884a4329513da318e7c418f2da8e59d Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Tue, 4 Aug 2020 13:01:53 -0500 Subject: [PATCH 24/30] update file credits --- Sources/ParseSwift/Objects/Fetchable.swift | 2 +- Sources/ParseSwift/Objects/ParseObject.swift | 2 +- Sources/ParseSwift/Objects/Queryable.swift | 2 +- Sources/ParseSwift/Objects/Saveable.swift | 2 +- Sources/ParseSwift/Parse Types/FindResult.swift | 2 +- Sources/ParseSwift/Parse Types/NoBody.swift | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Sources/ParseSwift/Objects/Fetchable.swift b/Sources/ParseSwift/Objects/Fetchable.swift index f51911b69..745e73093 100644 --- a/Sources/ParseSwift/Objects/Fetchable.swift +++ b/Sources/ParseSwift/Objects/Fetchable.swift @@ -2,7 +2,7 @@ // Fetchable.swift // ParseSwift // -// Created by Pranjal Satija on 7/18/20. +// Created by Florent Vilmart on 17-07-24. // Copyright © 2020 Parse. All rights reserved. // diff --git a/Sources/ParseSwift/Objects/ParseObject.swift b/Sources/ParseSwift/Objects/ParseObject.swift index bc20c454e..e6d24089f 100644 --- a/Sources/ParseSwift/Objects/ParseObject.swift +++ b/Sources/ParseSwift/Objects/ParseObject.swift @@ -2,7 +2,7 @@ // ParseObject.swift // ParseSwift // -// Created by Pranjal Satija on 7/18/20. +// Created by Florent Vilmart on 17-07-24. // Copyright © 2020 Parse. All rights reserved. // diff --git a/Sources/ParseSwift/Objects/Queryable.swift b/Sources/ParseSwift/Objects/Queryable.swift index 0099fac30..a84b8d38d 100644 --- a/Sources/ParseSwift/Objects/Queryable.swift +++ b/Sources/ParseSwift/Objects/Queryable.swift @@ -2,7 +2,7 @@ // Queryable.swift // ParseSwift // -// Created by Pranjal Satija on 7/18/20. +// Created by Florent Vilmart on 17-07-24. // Copyright © 2020 Parse. All rights reserved. // diff --git a/Sources/ParseSwift/Objects/Saveable.swift b/Sources/ParseSwift/Objects/Saveable.swift index c888e9a06..ed80538f0 100644 --- a/Sources/ParseSwift/Objects/Saveable.swift +++ b/Sources/ParseSwift/Objects/Saveable.swift @@ -2,7 +2,7 @@ // Saveable.swift // ParseSwift // -// Created by Pranjal Satija on 7/18/20. +// Created by Florent Vilmart on 17-07-24. // Copyright © 2020 Parse. All rights reserved. // diff --git a/Sources/ParseSwift/Parse Types/FindResult.swift b/Sources/ParseSwift/Parse Types/FindResult.swift index e7e0e87fc..31b115ee7 100644 --- a/Sources/ParseSwift/Parse Types/FindResult.swift +++ b/Sources/ParseSwift/Parse Types/FindResult.swift @@ -2,7 +2,7 @@ // FindResult.swift // ParseSwift // -// Created by Pranjal Satija on 8/4/20. +// Created by Florent Vilmart on 17-07-24. // Copyright © 2020 Parse Community. All rights reserved. // diff --git a/Sources/ParseSwift/Parse Types/NoBody.swift b/Sources/ParseSwift/Parse Types/NoBody.swift index cf85ad46d..42e175d6a 100644 --- a/Sources/ParseSwift/Parse Types/NoBody.swift +++ b/Sources/ParseSwift/Parse Types/NoBody.swift @@ -2,7 +2,7 @@ // NoBody.swift // ParseSwift // -// Created by Pranjal Satija on 7/18/20. +// Created by Florent Vilmart on 17-07-24. // Copyright © 2020 Parse. All rights reserved. // From 18c08a571abb86d6ce6eb23965d9383f0d6437c7 Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Tue, 4 Aug 2020 13:02:20 -0500 Subject: [PATCH 25/30] fix more tests --- Sources/ParseSwift/Coding/AnyDecodable.swift | 17 ++++++------ Sources/ParseSwift/Coding/AnyEncodable.swift | 28 ++++++++++---------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/Sources/ParseSwift/Coding/AnyDecodable.swift b/Sources/ParseSwift/Coding/AnyDecodable.swift index 50a4df79d..8c3990c83 100755 --- a/Sources/ParseSwift/Coding/AnyDecodable.swift +++ b/Sources/ParseSwift/Coding/AnyDecodable.swift @@ -45,22 +45,23 @@ extension AnyDecodable: _AnyDecodable {} extension _AnyDecodable { public init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() + if container.decodeNil() { self.init(()) - } else if let bool = try? container.decode(Bool.self) { - self.init(bool) + } else if let dictionary = try? container.decode([String: AnyCodable].self) { + self.init(dictionary.mapValues { $0.value }) + } else if let array = try? container.decode([AnyCodable].self) { + self.init(array.map { $0.value }) + } else if let string = try? container.decode(String.self) { + self.init(string) } else if let int = try? container.decode(Int.self) { self.init(int) } else if let uint = try? container.decode(UInt.self) { self.init(uint) } else if let double = try? container.decode(Double.self) { self.init(double) - } else if let string = try? container.decode(String.self) { - self.init(string) - } else if let array = try? container.decode([AnyCodable].self) { - self.init(array.map { $0.value }) - } else if let dictionary = try? container.decode([String: AnyCodable].self) { - self.init(dictionary.mapValues { $0.value }) + } else if let bool = try? container.decode(Bool.self) { + self.init(bool) } else { throw DecodingError.dataCorruptedError(in: container, debugDescription: "AnyCodable value cannot be decoded") diff --git a/Sources/ParseSwift/Coding/AnyEncodable.swift b/Sources/ParseSwift/Coding/AnyEncodable.swift index cf47555b8..e9489be44 100755 --- a/Sources/ParseSwift/Coding/AnyEncodable.swift +++ b/Sources/ParseSwift/Coding/AnyEncodable.swift @@ -65,10 +65,16 @@ extension _AnyEncodable { var container = encoder.singleValueContainer() switch self.value { - case is Void: - try container.encodeNil() - case let bool as Bool: - try container.encode(bool) + case let dictionary as [String: Any?]: + try container.encode(dictionary.mapValues { AnyCodable($0, dateEncodingStrategy: dateEncodingStrategy) }) + case let array as [Any?]: + try container.encode(array.map { AnyCodable($0, dateEncodingStrategy: dateEncodingStrategy) }) + case let url as URL: + try container.encode(url) + case let string as String: + try container.encode(string) + case let date as Date: + try container.encode(date) case let int as Int: try container.encode(int) case let int8 as Int8: @@ -93,16 +99,10 @@ extension _AnyEncodable { try container.encode(float) case let double as Double: try container.encode(double) - case let string as String: - try container.encode(string) - case let date as Date: - try container.encode(date) - case let url as URL: - try container.encode(url) - case let array as [Any?]: - try container.encode(array.map { AnyCodable($0, dateEncodingStrategy: dateEncodingStrategy) }) - case let dictionary as [String: Any?]: - try container.encode(dictionary.mapValues { AnyCodable($0, dateEncodingStrategy: dateEncodingStrategy) }) + case let bool as Bool: + try container.encode(bool) + case is Void: + try container.encodeNil() default: let context = EncodingError.Context(codingPath: container.codingPath, debugDescription: "AnyCodable value cannot be encoded") From 8189db8c1cdc41a64631cc76943b7b4ca586c188 Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Tue, 4 Aug 2020 20:20:41 -0500 Subject: [PATCH 26/30] address PR feedback --- .../Contents.swift | 2 +- .../Contents.swift | 2 +- .../3- Users.xcplaygroundpage/Contents.swift | 2 +- Sources/ParseSwift/Coding/Extensions.swift | 2 +- Sources/ParseSwift/Coding/ParseCoding.swift | 43 +++++++++++++------ Sources/ParseSwift/Coding/ParseEncoder.swift | 17 +++++--- Sources/ParseSwift/Parse.swift | 13 ++++-- Sources/ParseSwift/Storage/ParseStorage.swift | 3 +- .../Storage/PrimitiveObjectStore.swift | 4 +- .../ParseObjectBatchTests.swift | 2 +- .../ParseObjectCommandTests.swift | 2 +- Tests/ParseSwiftTests/ParseQueryTests.swift | 2 +- .../ParseUserCommandTests.swift | 4 +- 13 files changed, 60 insertions(+), 38 deletions(-) diff --git a/ParseSwift.playground/Pages/1- Your first Object.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/1- Your first Object.xcplaygroundpage/Contents.swift index b41efb313..e3a405538 100644 --- a/ParseSwift.playground/Pages/1- Your first Object.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/1- Your first Object.xcplaygroundpage/Contents.swift @@ -10,7 +10,7 @@ PlaygroundPage.current.needsIndefiniteExecution = true initializeParse() -struct GameScore: ParseSwift.ParseObject { +struct GameScore: ParseObject { //: Those are required for Object var objectId: String? var createdAt: Date? diff --git a/ParseSwift.playground/Pages/2- Finding Objects.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/2- Finding Objects.xcplaygroundpage/Contents.swift index 072ad9b59..2e6ee4aac 100644 --- a/ParseSwift.playground/Pages/2- Finding Objects.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/2- Finding Objects.xcplaygroundpage/Contents.swift @@ -10,7 +10,7 @@ PlaygroundPage.current.needsIndefiniteExecution = true initializeParse() -struct GameScore: ParseSwift.ParseObject { +struct GameScore: ParseObject { var objectId: String? var createdAt: Date? var updatedAt: Date? diff --git a/ParseSwift.playground/Pages/3- Users.xcplaygroundpage/Contents.swift b/ParseSwift.playground/Pages/3- Users.xcplaygroundpage/Contents.swift index ae7c082e5..566811e7d 100644 --- a/ParseSwift.playground/Pages/3- Users.xcplaygroundpage/Contents.swift +++ b/ParseSwift.playground/Pages/3- Users.xcplaygroundpage/Contents.swift @@ -7,7 +7,7 @@ PlaygroundPage.current.needsIndefiniteExecution = true import ParseSwift initializeParse() -struct User: ParseSwift.ParseUser { +struct User: ParseUser { //: Those are required for Object var objectId: String? var createdAt: Date? diff --git a/Sources/ParseSwift/Coding/Extensions.swift b/Sources/ParseSwift/Coding/Extensions.swift index f9c1e0f4e..3df6ead68 100644 --- a/Sources/ParseSwift/Coding/Extensions.swift +++ b/Sources/ParseSwift/Coding/Extensions.swift @@ -1,5 +1,5 @@ // -// File.swift +// Extensions.swift // // // Created by Pranjal Satija on 7/19/20. diff --git a/Sources/ParseSwift/Coding/ParseCoding.swift b/Sources/ParseSwift/Coding/ParseCoding.swift index 4cc3bb658..773f856cd 100644 --- a/Sources/ParseSwift/Coding/ParseCoding.swift +++ b/Sources/ParseSwift/Coding/ParseCoding.swift @@ -1,5 +1,5 @@ // -// ParseParseObject.swift +// ParseCoding.swift // ParseSwift // // Created by Florent Vilmart on 17-07-24. @@ -22,9 +22,9 @@ extension ParseCoding { } static func jsonDecoder() -> JSONDecoder { - let encoder = JSONDecoder() - encoder.dateDecodingStrategy = dateDecodingStrategy - return encoder + let decoder = JSONDecoder() + decoder.dateDecodingStrategy = dateDecodingStrategy + return decoder } static func parseEncoder(skipKeys: Bool = true) -> ParseEncoder { @@ -51,25 +51,40 @@ extension ParseCoding { static let jsonDateEncodingStrategy: JSONEncoder.DateEncodingStrategy = .custom(parseDateEncodingStrategy) - static let parseDateEncodingStrategy: AnyCodable.DateEncodingStrategy = { (date, enc) in - var container = enc.container(keyedBy: DateEncodingKeys.self) + static let parseDateEncodingStrategy: AnyCodable.DateEncodingStrategy = { (date, encoder) in + var container = encoder.container(keyedBy: DateEncodingKeys.self) try container.encode("Date", forKey: .type) let dateString = dateFormatter.string(from: date) try container.encode(dateString, forKey: .iso) } - static let dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .custom({ (dec) -> Date in + static let dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .custom({ (decoder) -> Date in do { - let container = try dec.singleValueContainer() + let container = try decoder.singleValueContainer() let decodedString = try container.decode(String.self) - return dateFormatter.date(from: decodedString)! + + if let date = dateFormatter.date(from: decodedString) { + return date + } else { + throw ParseError( + code: .unknownError, + message: "An invalid date string was provided when decoding dates." + ) + } } catch let error { - let container = try dec.container(keyedBy: DateEncodingKeys.self) - if let decoded = try container.decodeIfPresent(String.self, forKey: .iso) { - return dateFormatter.date(from: decoded)! + let container = try decoder.container(keyedBy: DateEncodingKeys.self) + + if + let decoded = try container.decodeIfPresent(String.self, forKey: .iso), + let date = dateFormatter.date(from: decoded) + { + return date + } else { + throw ParseError( + code: .unknownError, + message: "An invalid date string was provided when decoding dates." + ) } } - - throw ParseError(code: .unknownError, message: "unable to decode") }) } diff --git a/Sources/ParseSwift/Coding/ParseEncoder.swift b/Sources/ParseSwift/Coding/ParseEncoder.swift index 8c63e3b71..2aee59d35 100644 --- a/Sources/ParseSwift/Coding/ParseEncoder.swift +++ b/Sources/ParseSwift/Coding/ParseEncoder.swift @@ -12,7 +12,7 @@ import Foundation // MARK: ParseEncoder -public struct ParseEncoder { +internal struct ParseEncoder { let dateEncodingStrategy: AnyCodable.DateEncodingStrategy? let jsonEncoder: JSONEncoder let skippedKeys: Set @@ -37,12 +37,12 @@ public struct ParseEncoder { func encode(_ value: T) throws -> Data { let dictionary = try encodeToDictionary(value) - return try jsonEncoder.encode(AnyCodable(dictionary, dateEncodingStrategy: dateEncodingStrategy!)) + return try jsonEncoder.encode(AnyCodable(dictionary, dateEncodingStrategy: dateEncodingStrategy)) } func encode(_ array: [T]) throws -> Data { let dictionaries = try array.map { try encodeToDictionary($0) } - return try jsonEncoder.encode(AnyCodable(dictionaries, dateEncodingStrategy: dateEncodingStrategy!)) + return try jsonEncoder.encode(AnyCodable(dictionaries, dateEncodingStrategy: dateEncodingStrategy)) } } @@ -154,11 +154,11 @@ internal struct _ParseEncoderKeyedEncodingContainer: KeyedEncodi } mutating func superEncoder() -> Encoder { - fatalError() + fatalError("You can't encode supertypes yet.") } mutating func superEncoder(forKey key: Key) -> Encoder { - fatalError() + fatalError("You can't encode supertypes yet.") } } @@ -195,8 +195,11 @@ internal struct _ParseEncoderUnkeyedEncodingContainer: UnkeyedEncodingContainer var array: NSMutableArray { get { - // swiftlint:disable:next force_cast - dictionary[key] as! NSMutableArray + guard let array = dictionary[key] as? NSMutableArray else { + fatalError("There's no array available for unkeyed encoding.") + } + + return array } set { dictionary[key] = newValue } diff --git a/Sources/ParseSwift/Parse.swift b/Sources/ParseSwift/Parse.swift index 68c86f45a..8f26cb50e 100644 --- a/Sources/ParseSwift/Parse.swift +++ b/Sources/ParseSwift/Parse.swift @@ -8,10 +8,13 @@ internal struct ParseConfiguration { static var mountPath: String! } -public func initialize(applicationId: String, - clientKey: String? = nil, - masterKey: String? = nil, - serverURL: URL) { +public func initialize( + applicationId: String, + clientKey: String? = nil, + masterKey: String? = nil, + serverURL: URL, + primitiveObjectStore: PrimitiveObjectStore? = nil +) { ParseConfiguration.applicationId = applicationId ParseConfiguration.clientKey = clientKey ParseConfiguration.masterKey = masterKey @@ -19,4 +22,6 @@ public func initialize(applicationId: String, ParseConfiguration.mountPath = "/" + serverURL.pathComponents .filter { $0 != "/" } .joined(separator: "/") + + ParseStorage.shared.use(primitiveObjectStore ?? CodableInMemoryPrimitiveObjectStore()) } diff --git a/Sources/ParseSwift/Storage/ParseStorage.swift b/Sources/ParseSwift/Storage/ParseStorage.swift index 962032169..3f2f2008f 100644 --- a/Sources/ParseSwift/Storage/ParseStorage.swift +++ b/Sources/ParseSwift/Storage/ParseStorage.swift @@ -1,5 +1,5 @@ // -// File.swift +// ParseStorage.swift // // // Created by Pranjal Satija on 7/19/20. @@ -18,7 +18,6 @@ public struct ParseStorage { private mutating func requireBackingStore() { guard backingStore != nil else { print("You can't use ParseStorage without a backing store. An in-memory store is being used as a fallback.") - backingStore = CodableInMemoryPrimitiveObjectStore() return } } diff --git a/Sources/ParseSwift/Storage/PrimitiveObjectStore.swift b/Sources/ParseSwift/Storage/PrimitiveObjectStore.swift index 42895c90d..c34fc7be6 100644 --- a/Sources/ParseSwift/Storage/PrimitiveObjectStore.swift +++ b/Sources/ParseSwift/Storage/PrimitiveObjectStore.swift @@ -1,5 +1,5 @@ // -// File.swift +// PrimitiveObjectStore.swift // // // Created by Pranjal Satija on 7/19/20. @@ -44,7 +44,7 @@ extension KeychainStore: PrimitiveObjectStore { } func get(valueFor key: String) throws -> T? where T: Decodable { - return object(forKey: key) + object(forKey: key) } func set(_ object: T, for key: String) throws where T: Encodable { diff --git a/Tests/ParseSwiftTests/ParseObjectBatchTests.swift b/Tests/ParseSwiftTests/ParseObjectBatchTests.swift index 5946204ff..765e0fe49 100755 --- a/Tests/ParseSwiftTests/ParseObjectBatchTests.swift +++ b/Tests/ParseSwiftTests/ParseObjectBatchTests.swift @@ -12,7 +12,7 @@ import XCTest class ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_length - struct GameScore: ParseSwift.ParseObject { + struct GameScore: ParseObject { //: Those are required for Object var objectId: String? var createdAt: Date? diff --git a/Tests/ParseSwiftTests/ParseObjectCommandTests.swift b/Tests/ParseSwiftTests/ParseObjectCommandTests.swift index 61bcb9872..2e05aec5f 100644 --- a/Tests/ParseSwiftTests/ParseObjectCommandTests.swift +++ b/Tests/ParseSwiftTests/ParseObjectCommandTests.swift @@ -12,7 +12,7 @@ import XCTest class ParseObjectCommandTests: XCTestCase { // swiftlint:disable:this type_body_length - struct GameScore: ParseSwift.ParseObject { + struct GameScore: ParseObject { //: Those are required for Object var objectId: String? var createdAt: Date? diff --git a/Tests/ParseSwiftTests/ParseQueryTests.swift b/Tests/ParseSwiftTests/ParseQueryTests.swift index 18f782d51..09188c03a 100755 --- a/Tests/ParseSwiftTests/ParseQueryTests.swift +++ b/Tests/ParseSwiftTests/ParseQueryTests.swift @@ -12,7 +12,7 @@ import XCTest class ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length - struct GameScore: ParseSwift.ParseObject { + struct GameScore: ParseObject { //: Those are required for Object var objectId: String? var createdAt: Date? diff --git a/Tests/ParseSwiftTests/ParseUserCommandTests.swift b/Tests/ParseSwiftTests/ParseUserCommandTests.swift index 5f763def8..34f2980a0 100644 --- a/Tests/ParseSwiftTests/ParseUserCommandTests.swift +++ b/Tests/ParseSwiftTests/ParseUserCommandTests.swift @@ -12,7 +12,7 @@ import XCTest class ParseUserCommandTests: XCTestCase { // swiftlint:disable:this type_body_length - struct User: ParseSwift.ParseUser { + struct User: ParseUser { //: Those are required for Object var objectId: String? var createdAt: Date? @@ -28,7 +28,7 @@ class ParseUserCommandTests: XCTestCase { // swiftlint:disable:this type_body_le var customKey: String? } - struct LoginSignupResponse: ParseSwift.ParseUser { + struct LoginSignupResponse: ParseUser { var objectId: String? var createdAt: Date? var sessionToken: String From c28829c9c3be3b70b7ca0d5fe4101a6fa9bd7e5b Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Fri, 21 Aug 2020 22:17:15 -0500 Subject: [PATCH 27/30] add ParseEncoderTests --- ParseSwift.xcodeproj/project.pbxproj | 4 + Sources/ParseSwift/Coding/ParseEncoder.swift | 3 +- Tests/ParseSwiftTests/ParseEncoderTests.swift | 83 +++++++++++++++++++ 3 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 Tests/ParseSwiftTests/ParseEncoderTests.swift diff --git a/ParseSwift.xcodeproj/project.pbxproj b/ParseSwift.xcodeproj/project.pbxproj index ef7296014..cc24e6978 100644 --- a/ParseSwift.xcodeproj/project.pbxproj +++ b/ParseSwift.xcodeproj/project.pbxproj @@ -33,6 +33,7 @@ 912C9BF924D302B0009947C3 /* (null) in Sources */ = {isa = PBXBuildFile; }; 912C9BFD24D302B2009947C3 /* Parse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EE1F254B820063D731 /* Parse.swift */; }; 912C9C1624D302B2009947C3 /* (null) in Sources */ = {isa = PBXBuildFile; }; + F971F4F624DE381A006CB79B /* ParseEncoderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F971F4F524DE381A006CB79B /* ParseEncoderTests.swift */; }; F97B45CE24D9C6F200F4A88B /* ParseCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B424D9C6F200F4A88B /* ParseCoding.swift */; }; F97B45CF24D9C6F200F4A88B /* ParseCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B424D9C6F200F4A88B /* ParseCoding.swift */; }; F97B45D024D9C6F200F4A88B /* ParseCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B424D9C6F200F4A88B /* ParseCoding.swift */; }; @@ -230,6 +231,7 @@ 912C9BD824D3011F009947C3 /* ParseSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ParseSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 912C9BDA24D3011F009947C3 /* ParseSwift_tvOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ParseSwift_tvOS.h; sourceTree = ""; }; 912C9BDB24D3011F009947C3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + F971F4F524DE381A006CB79B /* ParseEncoderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseEncoderTests.swift; sourceTree = ""; }; F97B45B424D9C6F200F4A88B /* ParseCoding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseCoding.swift; sourceTree = ""; }; F97B45B524D9C6F200F4A88B /* AnyDecodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyDecodable.swift; sourceTree = ""; }; F97B45B624D9C6F200F4A88B /* ParseEncoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseEncoder.swift; sourceTree = ""; }; @@ -358,6 +360,7 @@ 4AA8076D1F794C1C008CD551 /* Info.plist */, 911DB12D24C4837E0027F3C7 /* APICommandTests.swift */, 4AA8076E1F794C1C008CD551 /* KeychainStoreTests.swift */, + F971F4F524DE381A006CB79B /* ParseEncoderTests.swift */, 70C7DC2024D20F190050419B /* ParseObjectBatchTests.swift */, 911DB13524C4FC100027F3C7 /* ParseObjectCommandTests.swift */, 70C7DC1F24D20F180050419B /* ParseQueryTests.swift */, @@ -887,6 +890,7 @@ 70C7DC2224D20F190050419B /* ParseObjectBatchTests.swift in Sources */, 7FFF552F2217E72A007C3B4E /* AnyCodableTests.swift in Sources */, 4AA807701F794C31008CD551 /* KeychainStoreTests.swift in Sources */, + F971F4F624DE381A006CB79B /* ParseEncoderTests.swift in Sources */, 70C7DC2124D20F190050419B /* ParseQueryTests.swift in Sources */, 70C7DC1E24D20E530050419B /* ParseUserCommandTests.swift in Sources */, 911DB13324C494390027F3C7 /* MockURLProtocol.swift in Sources */, diff --git a/Sources/ParseSwift/Coding/ParseEncoder.swift b/Sources/ParseSwift/Coding/ParseEncoder.swift index 2aee59d35..8338128f4 100644 --- a/Sources/ParseSwift/Coding/ParseEncoder.swift +++ b/Sources/ParseSwift/Coding/ParseEncoder.swift @@ -31,6 +31,7 @@ internal struct ParseEncoder { let encoder = _ParseEncoder(codingPath: [], dictionary: NSMutableDictionary(), skippingKeys: skippedKeys) try value.encode(to: encoder) + // The encoder always uses an `NSDictionary` with string keys. // swiftlint:disable:next force_cast return encoder.dictionary as! [AnyHashable: Any] } @@ -257,6 +258,6 @@ internal struct _ParseEncoderUnkeyedEncodingContainer: UnkeyedEncodingContainer } mutating func superEncoder() -> Encoder { - fatalError() + fatalError("You can't encode supertypes yet.") } } diff --git a/Tests/ParseSwiftTests/ParseEncoderTests.swift b/Tests/ParseSwiftTests/ParseEncoderTests.swift new file mode 100644 index 000000000..cc454d3c6 --- /dev/null +++ b/Tests/ParseSwiftTests/ParseEncoderTests.swift @@ -0,0 +1,83 @@ +// +// ParseEncoderTests.swift +// ParseSwiftTests +// +// Created by Pranjal Satija on 8/7/20. +// Copyright © 2020 Parse Community. All rights reserved. +// + +import XCTest +@testable import ParseSwift + +class ParseEncoderTests: XCTestCase { + struct Address: Codable { + let street: String + let city: String + } + + struct Name: Codable { + let first: String + let last: String + } + + struct Person: Codable { + let addresses: [String: Address] + let age: Int + let name: Name + let nicknames: [Name] + let phoneNumbers: [String] + } + + func parseEncoding(for object: T) -> Data { + let encoder = ParseEncoder() + encoder.jsonEncoder.outputFormatting = .sortedKeys + + guard let encoding = try? encoder.encode(object) else { + XCTFail("Couldn't get a Parse encoding.") + return Data() + } + + return encoding + } + + func referenceEncoding(for object: T) -> Data { + let encoder = JSONEncoder() + encoder.outputFormatting = .sortedKeys + + guard let encoding = try? encoder.encode(object) else { + XCTFail("Couldn't get a reference encoding.") + return Data() + } + + return encoding + } + + func test_encodingScalarValue() { + let encoded = parseEncoding(for: 5) + let reference = referenceEncoding(for: ["": 5]) + XCTAssertEqual(encoded, reference) + } + + func test_encodingComplexValue() { + let value = Person( + addresses: [ + "home": Address(street: "Parse St.", city: "San Francisco"), + "work": Address(street: "Server Ave.", city: "Seattle") + ], + age: 21, + name: Name(first: "Parse", last: "User"), + nicknames: [ + Name(first: "Swift", last: "Developer"), + Name(first: "iOS", last: "Engineer") + ], + phoneNumbers: [ + "1-800-PARSE", + "1-999-SWIFT" + ] + ) + + let encoded = parseEncoding(for: value) + let reference = referenceEncoding(for: value) + XCTAssertEqual(encoded, reference) + } +} From f621266d94bb7c9bad55ba4d5c16136f1056313a Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Fri, 21 Aug 2020 22:25:32 -0500 Subject: [PATCH 28/30] bump test host deployment target --- ParseSwift.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ParseSwift.xcodeproj/project.pbxproj b/ParseSwift.xcodeproj/project.pbxproj index cc24e6978..baba90c63 100644 --- a/ParseSwift.xcodeproj/project.pbxproj +++ b/ParseSwift.xcodeproj/project.pbxproj @@ -1072,7 +1072,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = TestHost/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.parse.TestHost; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1087,7 +1087,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; INFOPLIST_FILE = TestHost/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.parse.TestHost; PRODUCT_NAME = "$(TARGET_NAME)"; From a8c43acb249333ef971062d94eb442256e2c3afb Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Fri, 21 Aug 2020 22:33:42 -0500 Subject: [PATCH 29/30] add availability check --- Tests/ParseSwiftTests/ParseEncoderTests.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Tests/ParseSwiftTests/ParseEncoderTests.swift b/Tests/ParseSwiftTests/ParseEncoderTests.swift index cc454d3c6..17b4797ea 100644 --- a/Tests/ParseSwiftTests/ParseEncoderTests.swift +++ b/Tests/ParseSwiftTests/ParseEncoderTests.swift @@ -9,6 +9,9 @@ import XCTest @testable import ParseSwift +// This is necessary because of the .sortedKeys output formatting given to the JSONEncoder +// That API is only available on macOS 10.13 and up. +@available(macOS 13, *) class ParseEncoderTests: XCTestCase { struct Address: Codable { let street: String From ee7e1fef07995584db86b978fddd9778fee940a1 Mon Sep 17 00:00:00 2001 From: Pranjal Satija Date: Fri, 21 Aug 2020 23:51:54 -0500 Subject: [PATCH 30/30] increase coverage target --- .codecov.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.codecov.yml b/.codecov.yml index e7d5ee618..50064ab5b 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -6,6 +6,6 @@ coverage: changes: false project: default: - target: 45 + target: 52 comment: require_changes: true