From edd71f86a16087d783ddd518cc77766424c05214 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Sat, 29 Feb 2020 18:00:33 +0000 Subject: [PATCH 01/15] feat: support Swift 5 BREAKING CHANGE: Swift 3/4 is no longer supported Closes #52 Closes #53 Closes #54 --- CHANGELOG.md | 7 +++++++ QueryKit.podspec | 1 + QueryKit.xcodeproj/project.pbxproj | 7 +++---- QueryKit/Attribute.swift | 4 ++-- QueryKit/QuerySet.swift | 10 +++++----- 5 files changed, 18 insertions(+), 11 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..d4638af --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ +# QueryKit Changelog + +## Master + +### Breaking + +* Drops support for Swift 3 and Swift 4. Swift 5 or newer must be used. diff --git a/QueryKit.podspec b/QueryKit.podspec index f80331f..07d46a1 100644 --- a/QueryKit.podspec +++ b/QueryKit.podspec @@ -8,6 +8,7 @@ Pod::Spec.new do |spec| spec.social_media_url = 'https://twitter.com/QueryKit' spec.source = { :git => 'https://github.com/QueryKit/QueryKit.git', :tag => "#{spec.version}" } spec.requires_arc = true + spec.swift_versions = ['5.0', '5.1'] spec.ios.deployment_target = '8.0' spec.osx.deployment_target = '10.9' spec.watchos.deployment_target = '2.0' diff --git a/QueryKit.xcodeproj/project.pbxproj b/QueryKit.xcodeproj/project.pbxproj index bd202ab..e30fa30 100644 --- a/QueryKit.xcodeproj/project.pbxproj +++ b/QueryKit.xcodeproj/project.pbxproj @@ -190,6 +190,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, ); mainGroup = 279ED5761BED09EB0011CA09; @@ -297,6 +298,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; TVOS_DEPLOYMENT_TARGET = 9.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -342,6 +344,7 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 5.0; TVOS_DEPLOYMENT_TARGET = 9.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -368,7 +371,6 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -390,7 +392,6 @@ PRODUCT_BUNDLE_IDENTIFIER = org.querykit.QueryKit; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; - SWIFT_VERSION = 3.0; }; name = Release; }; @@ -403,7 +404,6 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = org.querykit.QueryKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -416,7 +416,6 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = org.querykit.QueryKitTests; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; }; name = Release; }; diff --git a/QueryKit/Attribute.swift b/QueryKit/Attribute.swift index e39f0f0..078707b 100644 --- a/QueryKit/Attribute.swift +++ b/QueryKit/Attribute.swift @@ -111,11 +111,11 @@ prefix public func ! (left: Attribute) -> NSPredicate { } public extension QuerySet { - public func filter(_ attribute:Attribute) -> QuerySet { + func filter(_ attribute:Attribute) -> QuerySet { return filter(attribute == true) } - public func exclude(_ attribute:Attribute) -> QuerySet { + func exclude(_ attribute:Attribute) -> QuerySet { return filter(attribute == false) } } diff --git a/QueryKit/QuerySet.swift b/QueryKit/QuerySet.swift index 7ee7745..c1f0ccd 100644 --- a/QueryKit/QuerySet.swift +++ b/QueryKit/QuerySet.swift @@ -4,19 +4,19 @@ import CoreData /// Represents a lazy database lookup for a set of objects. open class QuerySet : Equatable { /// Returns the managed object context that will be used to execute any requests. - open let context:NSManagedObjectContext + public let context: NSManagedObjectContext /// Returns the name of the entity the request is configured to fetch. - open let entityName:String + public let entityName: String /// Returns the sort descriptors of the receiver. - open let sortDescriptors:[NSSortDescriptor] + public let sortDescriptors: [NSSortDescriptor] /// Returns the predicate of the receiver. - open let predicate:NSPredicate? + public let predicate: NSPredicate? /// The range of the query, allows you to offset and limit a query - open let range: Range? + public let range: Range? // MARK: Initialization From 86508067667613a1f8f098e7f899c016315299e8 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Sat, 29 Feb 2020 18:01:12 +0000 Subject: [PATCH 02/15] refactor: switch to Xcode 11 defaults --- QueryKit.xcodeproj/project.pbxproj | 22 ++++++++++++++--- .../xcshareddata/xcschemes/QueryKit.xcscheme | 24 ++++++++----------- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/QueryKit.xcodeproj/project.pbxproj b/QueryKit.xcodeproj/project.pbxproj index e30fa30..4a045db 100644 --- a/QueryKit.xcodeproj/project.pbxproj +++ b/QueryKit.xcodeproj/project.pbxproj @@ -172,7 +172,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0710; - LastUpgradeCheck = 0800; + LastUpgradeCheck = 1130; ORGANIZATIONNAME = QueryKit; TargetAttributes = { 279ED57F1BED09EB0011CA09 = { @@ -187,11 +187,11 @@ }; buildConfigurationList = 279ED57A1BED09EB0011CA09 /* Build configuration list for PBXProject "QueryKit" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( - English, en, + Base, ); mainGroup = 279ED5761BED09EB0011CA09; productRefGroup = 279ED5811BED09EB0011CA09 /* Products */; @@ -261,14 +261,22 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -314,14 +322,22 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; diff --git a/QueryKit.xcodeproj/xcshareddata/xcschemes/QueryKit.xcscheme b/QueryKit.xcodeproj/xcshareddata/xcschemes/QueryKit.xcscheme index 434d561..07cd6fc 100644 --- a/QueryKit.xcodeproj/xcshareddata/xcschemes/QueryKit.xcscheme +++ b/QueryKit.xcodeproj/xcshareddata/xcschemes/QueryKit.xcscheme @@ -1,6 +1,6 @@ + + + + @@ -39,17 +48,6 @@ - - - - - - - - Date: Sat, 29 Feb 2020 18:16:46 +0000 Subject: [PATCH 03/15] feat: migrate to swift package manager --- .gitignore | 2 + Configurations/LICENSE | 22 - .../UniversalFramework_Base.xcconfig | 25 - .../UniversalFramework_Framework.xcconfig | 32 -- .../UniversalFramework_Test.xcconfig | 18 - Package.swift | 13 + QueryKit.podspec | 2 +- QueryKit.xcodeproj/project.pbxproj | 471 ------------------ .../contents.xcworkspacedata | 7 - .../xcshareddata/xcschemes/QueryKit.xcscheme | 95 ---- QueryKit/Info.plist | 28 -- QueryKitTests/Info.plist | 24 - .../QueryKit}/Attribute.swift | 0 .../QueryKit}/Expression.swift | 0 .../QueryKit}/Predicate.swift | 0 {QueryKit => Sources/QueryKit}/QueryKit.h | 0 {QueryKit => Sources/QueryKit}/QuerySet.swift | 8 +- .../QueryKit}/SortDescriptor.swift | 0 .../QueryKitTests}/AttributeTests.swift | 0 .../QueryKitTests}/ExpressionTests.swift | 0 .../QueryKitTests}/PredicateTests.swift | 0 .../QueryKitTests}/QueryKitTests.swift | 0 .../QueryKitTests}/QuerySetTests.swift | 2 +- .../QueryKitTests}/SortDescriptorTests.swift | 0 24 files changed, 24 insertions(+), 725 deletions(-) delete mode 100644 Configurations/LICENSE delete mode 100644 Configurations/UniversalFramework_Base.xcconfig delete mode 100644 Configurations/UniversalFramework_Framework.xcconfig delete mode 100644 Configurations/UniversalFramework_Test.xcconfig create mode 100644 Package.swift delete mode 100644 QueryKit.xcodeproj/project.pbxproj delete mode 100644 QueryKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 QueryKit.xcodeproj/xcshareddata/xcschemes/QueryKit.xcscheme delete mode 100644 QueryKit/Info.plist delete mode 100644 QueryKitTests/Info.plist rename {QueryKit => Sources/QueryKit}/Attribute.swift (100%) rename {QueryKit => Sources/QueryKit}/Expression.swift (100%) rename {QueryKit => Sources/QueryKit}/Predicate.swift (100%) rename {QueryKit => Sources/QueryKit}/QueryKit.h (100%) rename {QueryKit => Sources/QueryKit}/QuerySet.swift (97%) rename {QueryKit => Sources/QueryKit}/SortDescriptor.swift (100%) rename {QueryKitTests => Tests/QueryKitTests}/AttributeTests.swift (100%) rename {QueryKitTests => Tests/QueryKitTests}/ExpressionTests.swift (100%) rename {QueryKitTests => Tests/QueryKitTests}/PredicateTests.swift (100%) rename {QueryKitTests => Tests/QueryKitTests}/QueryKitTests.swift (100%) rename {QueryKitTests => Tests/QueryKitTests}/QuerySetTests.swift (98%) rename {QueryKitTests => Tests/QueryKitTests}/SortDescriptorTests.swift (100%) diff --git a/.gitignore b/.gitignore index 47042c2..b69aff0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ .DS_Store xcuserdata +*.xcodeproj/ +.build/ diff --git a/Configurations/LICENSE b/Configurations/LICENSE deleted file mode 100644 index ad21101..0000000 --- a/Configurations/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Marius Rackwitz - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/Configurations/UniversalFramework_Base.xcconfig b/Configurations/UniversalFramework_Base.xcconfig deleted file mode 100644 index 261e2b2..0000000 --- a/Configurations/UniversalFramework_Base.xcconfig +++ /dev/null @@ -1,25 +0,0 @@ -// -// Put this file alongside to the other both, as it contains what -// both have in common. Don't rename this file. -// -// Copyright (c) 2014-2015 Marius Rackwitz. All rights reserved. -// - -// Make it universal -SUPPORTED_PLATFORMS = macosx iphonesimulator iphoneos watchos watchsimulator appletvos appletvsimulator -VALID_ARCHS[sdk=macosx*] = i386 x86_64 -VALID_ARCHS[sdk=iphoneos*] = arm64 armv7 armv7s -VALID_ARCHS[sdk=iphonesimulator*] = i386 x86_64 -VALID_ARCHS[sdk=watchos*] = armv7k -VALID_ARCHS[sdk=watchsimulator*] = i386 -VALID_ARCHS[sdk=appletv*] = arm64 -VALID_ARCHS[sdk=appletvsimulator*] = x86_64 - -// Dynamic linking uses different default copy paths -LD_RUNPATH_SEARCH_PATHS[sdk=macosx*] = $(inherited) '@executable_path/../Frameworks' '@loader_path/Frameworks' -LD_RUNPATH_SEARCH_PATHS[sdk=iphoneos*] = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' -LD_RUNPATH_SEARCH_PATHS[sdk=iphonesimulator*] = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' -LD_RUNPATH_SEARCH_PATHS[sdk=watchos*] = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' -LD_RUNPATH_SEARCH_PATHS[sdk=watchsimulator*] = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' -LD_RUNPATH_SEARCH_PATHS[sdk=appletvos*] = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' -LD_RUNPATH_SEARCH_PATHS[sdk=appletvsimulator*] = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' diff --git a/Configurations/UniversalFramework_Framework.xcconfig b/Configurations/UniversalFramework_Framework.xcconfig deleted file mode 100644 index 1406c7a..0000000 --- a/Configurations/UniversalFramework_Framework.xcconfig +++ /dev/null @@ -1,32 +0,0 @@ -// -// Inherit from this config in your framework target. -// -// Copyright (c) 2014-2015 Marius Rackwitz. All rights reserved. -// - -#include "UniversalFramework_Base.xcconfig" - -// OSX-specific default settings -FRAMEWORK_VERSION[sdk=macosx*] = A -COMBINE_HIDPI_IMAGES[sdk=macosx*] = YES - -// iOS-specific default settings -CODE_SIGN_IDENTITY[sdk=iphoneos*] = iPhone Developer -TARGETED_DEVICE_FAMILY[sdk=iphonesimulator*] = 1,2 -TARGETED_DEVICE_FAMILY[sdk=iphone*] = 1,2 - -// TV-specific default settings -TARGETED_DEVICE_FAMILY[sdk=appletvsimulator*] = 3 -TARGETED_DEVICE_FAMILY[sdk=appletv*] = 3 - -// Watch-specific default settings -TARGETED_DEVICE_FAMILY[sdk=watchsimulator*] = 4 -TARGETED_DEVICE_FAMILY[sdk=watch*] = 4 - -ENABLE_BITCODE[sdk=macosx*] = NO -ENABLE_BITCODE[sdk=watchsimulator*] = YES -ENABLE_BITCODE[sdk=watch*] = YES -ENABLE_BITCODE[sdk=iphonesimulator*] = YES -ENABLE_BITCODE[sdk=iphone*] = YES -ENABLE_BITCODE[sdk=appletvsimulator*] = YES -ENABLE_BITCODE[sdk=appletv*] = YES diff --git a/Configurations/UniversalFramework_Test.xcconfig b/Configurations/UniversalFramework_Test.xcconfig deleted file mode 100644 index 0c5f845..0000000 --- a/Configurations/UniversalFramework_Test.xcconfig +++ /dev/null @@ -1,18 +0,0 @@ -// -// Inherit from this config in the test target for your framework. -// -// Copyright (c) 2014-2015 Marius Rackwitz. All rights reserved. -// - -#include "UniversalFramework_Base.xcconfig" - -FRAMEWORK_SEARCH_PATHS = $(inherited) '$(PLATFORM_DIR)/Developer/Library/Frameworks' - -// Yep. -LD_RUNPATH_SEARCH_PATHS[sdk=macosx*] = $(inherited) '@executable_path/../Frameworks' '@loader_path/../Frameworks' -LD_RUNPATH_SEARCH_PATHS[sdk=iphoneos*] = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' -LD_RUNPATH_SEARCH_PATHS[sdk=iphonesimulator*] = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' -LD_RUNPATH_SEARCH_PATHS[sdk=watchos*] = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' -LD_RUNPATH_SEARCH_PATHS[sdk=watchsimulator*] = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' -LD_RUNPATH_SEARCH_PATHS[sdk=appletvos*] = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' -LD_RUNPATH_SEARCH_PATHS[sdk=appletvsimulator*] = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..d661163 --- /dev/null +++ b/Package.swift @@ -0,0 +1,13 @@ +// swift-tools-version:5.0 +import PackageDescription + + +let package = Package( + name: "QueryKit", + products: [ + ], + targets: [ + .target(name: "QueryKit", dependencies: []), + .testTarget(name: "QueryKitTests", dependencies: ["QueryKit"]), + ] +) diff --git a/QueryKit.podspec b/QueryKit.podspec index 07d46a1..26b43ea 100644 --- a/QueryKit.podspec +++ b/QueryKit.podspec @@ -14,6 +14,6 @@ Pod::Spec.new do |spec| spec.watchos.deployment_target = '2.0' spec.tvos.deployment_target = '9.0' spec.frameworks = 'CoreData' - spec.source_files = 'QueryKit/*.swift' + spec.source_files = 'Sources/QueryKit/*.swift' end diff --git a/QueryKit.xcodeproj/project.pbxproj b/QueryKit.xcodeproj/project.pbxproj deleted file mode 100644 index 4a045db..0000000 --- a/QueryKit.xcodeproj/project.pbxproj +++ /dev/null @@ -1,471 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 279ED5841BED09EB0011CA09 /* QueryKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 279ED5831BED09EB0011CA09 /* QueryKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 279ED58B1BED09EB0011CA09 /* QueryKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 279ED5801BED09EB0011CA09 /* QueryKit.framework */; }; - 279ED5901BED09EB0011CA09 /* QueryKitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279ED58F1BED09EB0011CA09 /* QueryKitTests.swift */; }; - 279ED59F1BED0A5C0011CA09 /* SortDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279ED59A1BED0A5C0011CA09 /* SortDescriptor.swift */; }; - 279ED5A01BED0A5C0011CA09 /* QuerySet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279ED59B1BED0A5C0011CA09 /* QuerySet.swift */; }; - 279ED5A11BED0A5C0011CA09 /* Predicate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279ED59C1BED0A5C0011CA09 /* Predicate.swift */; }; - 279ED5A21BED0A5C0011CA09 /* Expression.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279ED59D1BED0A5C0011CA09 /* Expression.swift */; }; - 279ED5A31BED0A5C0011CA09 /* Attribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279ED59E1BED0A5C0011CA09 /* Attribute.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 279ED58C1BED09EB0011CA09 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 279ED5771BED09EB0011CA09 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 279ED57F1BED09EB0011CA09; - remoteInfo = QueryKit; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 279ED5801BED09EB0011CA09 /* QueryKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = QueryKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 279ED5831BED09EB0011CA09 /* QueryKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = QueryKit.h; sourceTree = ""; }; - 279ED5851BED09EB0011CA09 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 279ED58A1BED09EB0011CA09 /* QueryKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = QueryKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 279ED58F1BED09EB0011CA09 /* QueryKitTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryKitTests.swift; sourceTree = ""; }; - 279ED5911BED09EB0011CA09 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 279ED59A1BED0A5C0011CA09 /* SortDescriptor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SortDescriptor.swift; sourceTree = ""; }; - 279ED59B1BED0A5C0011CA09 /* QuerySet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QuerySet.swift; sourceTree = ""; }; - 279ED59C1BED0A5C0011CA09 /* Predicate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Predicate.swift; sourceTree = ""; }; - 279ED59D1BED0A5C0011CA09 /* Expression.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Expression.swift; sourceTree = ""; }; - 279ED59E1BED0A5C0011CA09 /* Attribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Attribute.swift; sourceTree = ""; }; - 279ED5A61BED0AA50011CA09 /* UniversalFramework_Base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = UniversalFramework_Base.xcconfig; sourceTree = ""; }; - 279ED5A71BED0AA50011CA09 /* UniversalFramework_Framework.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = UniversalFramework_Framework.xcconfig; sourceTree = ""; }; - 279ED5A81BED0AA50011CA09 /* UniversalFramework_Test.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = UniversalFramework_Test.xcconfig; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 279ED57C1BED09EB0011CA09 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 279ED5871BED09EB0011CA09 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 279ED58B1BED09EB0011CA09 /* QueryKit.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 279ED5761BED09EB0011CA09 = { - isa = PBXGroup; - children = ( - 279ED5A41BED0AA50011CA09 /* Configurations */, - 279ED5821BED09EB0011CA09 /* QueryKit */, - 279ED58E1BED09EB0011CA09 /* QueryKitTests */, - 279ED5811BED09EB0011CA09 /* Products */, - ); - sourceTree = ""; - }; - 279ED5811BED09EB0011CA09 /* Products */ = { - isa = PBXGroup; - children = ( - 279ED5801BED09EB0011CA09 /* QueryKit.framework */, - 279ED58A1BED09EB0011CA09 /* QueryKitTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 279ED5821BED09EB0011CA09 /* QueryKit */ = { - isa = PBXGroup; - children = ( - 279ED5831BED09EB0011CA09 /* QueryKit.h */, - 279ED59B1BED0A5C0011CA09 /* QuerySet.swift */, - 279ED59E1BED0A5C0011CA09 /* Attribute.swift */, - 279ED59D1BED0A5C0011CA09 /* Expression.swift */, - 279ED59A1BED0A5C0011CA09 /* SortDescriptor.swift */, - 279ED59C1BED0A5C0011CA09 /* Predicate.swift */, - 279ED5851BED09EB0011CA09 /* Info.plist */, - ); - path = QueryKit; - sourceTree = ""; - }; - 279ED58E1BED09EB0011CA09 /* QueryKitTests */ = { - isa = PBXGroup; - children = ( - 279ED58F1BED09EB0011CA09 /* QueryKitTests.swift */, - 279ED5911BED09EB0011CA09 /* Info.plist */, - ); - path = QueryKitTests; - sourceTree = ""; - }; - 279ED5A41BED0AA50011CA09 /* Configurations */ = { - isa = PBXGroup; - children = ( - 279ED5A61BED0AA50011CA09 /* UniversalFramework_Base.xcconfig */, - 279ED5A71BED0AA50011CA09 /* UniversalFramework_Framework.xcconfig */, - 279ED5A81BED0AA50011CA09 /* UniversalFramework_Test.xcconfig */, - ); - path = Configurations; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 279ED57D1BED09EB0011CA09 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 279ED5841BED09EB0011CA09 /* QueryKit.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 279ED57F1BED09EB0011CA09 /* QueryKit */ = { - isa = PBXNativeTarget; - buildConfigurationList = 279ED5941BED09EB0011CA09 /* Build configuration list for PBXNativeTarget "QueryKit" */; - buildPhases = ( - 279ED57B1BED09EB0011CA09 /* Sources */, - 279ED57C1BED09EB0011CA09 /* Frameworks */, - 279ED57D1BED09EB0011CA09 /* Headers */, - 279ED57E1BED09EB0011CA09 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = QueryKit; - productName = QueryKit; - productReference = 279ED5801BED09EB0011CA09 /* QueryKit.framework */; - productType = "com.apple.product-type.framework"; - }; - 279ED5891BED09EB0011CA09 /* QueryKitTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 279ED5971BED09EB0011CA09 /* Build configuration list for PBXNativeTarget "QueryKitTests" */; - buildPhases = ( - 279ED5861BED09EB0011CA09 /* Sources */, - 279ED5871BED09EB0011CA09 /* Frameworks */, - 279ED5881BED09EB0011CA09 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 279ED58D1BED09EB0011CA09 /* PBXTargetDependency */, - ); - name = QueryKitTests; - productName = QueryKitTests; - productReference = 279ED58A1BED09EB0011CA09 /* QueryKitTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 279ED5771BED09EB0011CA09 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 0710; - LastUpgradeCheck = 1130; - ORGANIZATIONNAME = QueryKit; - TargetAttributes = { - 279ED57F1BED09EB0011CA09 = { - CreatedOnToolsVersion = 7.1; - LastSwiftMigration = 0800; - }; - 279ED5891BED09EB0011CA09 = { - CreatedOnToolsVersion = 7.1; - LastSwiftMigration = 0800; - }; - }; - }; - buildConfigurationList = 279ED57A1BED09EB0011CA09 /* Build configuration list for PBXProject "QueryKit" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 279ED5761BED09EB0011CA09; - productRefGroup = 279ED5811BED09EB0011CA09 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 279ED57F1BED09EB0011CA09 /* QueryKit */, - 279ED5891BED09EB0011CA09 /* QueryKitTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 279ED57E1BED09EB0011CA09 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 279ED5881BED09EB0011CA09 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 279ED57B1BED09EB0011CA09 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 279ED5A31BED0A5C0011CA09 /* Attribute.swift in Sources */, - 279ED59F1BED0A5C0011CA09 /* SortDescriptor.swift in Sources */, - 279ED5A11BED0A5C0011CA09 /* Predicate.swift in Sources */, - 279ED5A01BED0A5C0011CA09 /* QuerySet.swift in Sources */, - 279ED5A21BED0A5C0011CA09 /* Expression.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 279ED5861BED09EB0011CA09 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 279ED5901BED09EB0011CA09 /* QueryKitTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 279ED58D1BED09EB0011CA09 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 279ED57F1BED09EB0011CA09 /* QueryKit */; - targetProxy = 279ED58C1BED09EB0011CA09 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin XCBuildConfiguration section */ - 279ED5921BED09EB0011CA09 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MACOSX_DEPLOYMENT_TARGET = 10.11; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TVOS_DEPLOYMENT_TARGET = 9.0; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - WATCHOS_DEPLOYMENT_TARGET = 2.0; - }; - name = Debug; - }; - 279ED5931BED09EB0011CA09 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; - MACOSX_DEPLOYMENT_TARGET = 10.11; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 5.0; - TVOS_DEPLOYMENT_TARGET = 9.0; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - WATCHOS_DEPLOYMENT_TARGET = 2.0; - }; - name = Release; - }; - 279ED5951BED09EB0011CA09 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 279ED5A71BED0AA50011CA09 /* UniversalFramework_Framework.xcconfig */; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = ""; - COMBINE_HIDPI_IMAGES = YES; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_VERSION = A; - INFOPLIST_FILE = QueryKit/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = org.querykit.QueryKit; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 279ED5961BED09EB0011CA09 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 279ED5A71BED0AA50011CA09 /* UniversalFramework_Framework.xcconfig */; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = ""; - COMBINE_HIDPI_IMAGES = YES; - DEFINES_MODULE = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - FRAMEWORK_VERSION = A; - INFOPLIST_FILE = QueryKit/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = org.querykit.QueryKit; - PRODUCT_NAME = "$(TARGET_NAME)"; - SKIP_INSTALL = YES; - }; - name = Release; - }; - 279ED5981BED09EB0011CA09 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 279ED5A81BED0AA50011CA09 /* UniversalFramework_Test.xcconfig */; - buildSettings = { - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = QueryKitTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = org.querykit.QueryKitTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 279ED5991BED09EB0011CA09 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 279ED5A81BED0AA50011CA09 /* UniversalFramework_Test.xcconfig */; - buildSettings = { - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = QueryKitTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = org.querykit.QueryKitTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 279ED57A1BED09EB0011CA09 /* Build configuration list for PBXProject "QueryKit" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 279ED5921BED09EB0011CA09 /* Debug */, - 279ED5931BED09EB0011CA09 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 279ED5941BED09EB0011CA09 /* Build configuration list for PBXNativeTarget "QueryKit" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 279ED5951BED09EB0011CA09 /* Debug */, - 279ED5961BED09EB0011CA09 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 279ED5971BED09EB0011CA09 /* Build configuration list for PBXNativeTarget "QueryKitTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 279ED5981BED09EB0011CA09 /* Debug */, - 279ED5991BED09EB0011CA09 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 279ED5771BED09EB0011CA09 /* Project object */; -} diff --git a/QueryKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/QueryKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1639ef8..0000000 --- a/QueryKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/QueryKit.xcodeproj/xcshareddata/xcschemes/QueryKit.xcscheme b/QueryKit.xcodeproj/xcshareddata/xcschemes/QueryKit.xcscheme deleted file mode 100644 index 07cd6fc..0000000 --- a/QueryKit.xcodeproj/xcshareddata/xcschemes/QueryKit.xcscheme +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/QueryKit/Info.plist b/QueryKit/Info.plist deleted file mode 100644 index f2e8865..0000000 --- a/QueryKit/Info.plist +++ /dev/null @@ -1,28 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSHumanReadableCopyright - Copyright © 2015 QueryKit. All rights reserved. - NSPrincipalClass - - - diff --git a/QueryKitTests/Info.plist b/QueryKitTests/Info.plist deleted file mode 100644 index ba72822..0000000 --- a/QueryKitTests/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - - diff --git a/QueryKit/Attribute.swift b/Sources/QueryKit/Attribute.swift similarity index 100% rename from QueryKit/Attribute.swift rename to Sources/QueryKit/Attribute.swift diff --git a/QueryKit/Expression.swift b/Sources/QueryKit/Expression.swift similarity index 100% rename from QueryKit/Expression.swift rename to Sources/QueryKit/Expression.swift diff --git a/QueryKit/Predicate.swift b/Sources/QueryKit/Predicate.swift similarity index 100% rename from QueryKit/Predicate.swift rename to Sources/QueryKit/Predicate.swift diff --git a/QueryKit/QueryKit.h b/Sources/QueryKit/QueryKit.h similarity index 100% rename from QueryKit/QueryKit.h rename to Sources/QueryKit/QueryKit.h diff --git a/QueryKit/QuerySet.swift b/Sources/QueryKit/QuerySet.swift similarity index 97% rename from QueryKit/QuerySet.swift rename to Sources/QueryKit/QuerySet.swift index c1f0ccd..8fa51d6 100644 --- a/QueryKit/QuerySet.swift +++ b/Sources/QueryKit/QuerySet.swift @@ -140,7 +140,13 @@ extension QuerySet { return items.first } - public subscript(range:Range) -> QuerySet { + public subscript(range: ClosedRange) -> QuerySet { + get { + return self[Range(range)] + } + } + + public subscript(range: Range) -> QuerySet { get { var fullRange = range diff --git a/QueryKit/SortDescriptor.swift b/Sources/QueryKit/SortDescriptor.swift similarity index 100% rename from QueryKit/SortDescriptor.swift rename to Sources/QueryKit/SortDescriptor.swift diff --git a/QueryKitTests/AttributeTests.swift b/Tests/QueryKitTests/AttributeTests.swift similarity index 100% rename from QueryKitTests/AttributeTests.swift rename to Tests/QueryKitTests/AttributeTests.swift diff --git a/QueryKitTests/ExpressionTests.swift b/Tests/QueryKitTests/ExpressionTests.swift similarity index 100% rename from QueryKitTests/ExpressionTests.swift rename to Tests/QueryKitTests/ExpressionTests.swift diff --git a/QueryKitTests/PredicateTests.swift b/Tests/QueryKitTests/PredicateTests.swift similarity index 100% rename from QueryKitTests/PredicateTests.swift rename to Tests/QueryKitTests/PredicateTests.swift diff --git a/QueryKitTests/QueryKitTests.swift b/Tests/QueryKitTests/QueryKitTests.swift similarity index 100% rename from QueryKitTests/QueryKitTests.swift rename to Tests/QueryKitTests/QueryKitTests.swift diff --git a/QueryKitTests/QuerySetTests.swift b/Tests/QueryKitTests/QuerySetTests.swift similarity index 98% rename from QueryKitTests/QuerySetTests.swift rename to Tests/QueryKitTests/QuerySetTests.swift index d1dbc3b..0653a5a 100644 --- a/QueryKitTests/QuerySetTests.swift +++ b/Tests/QueryKitTests/QuerySetTests.swift @@ -63,7 +63,7 @@ class QuerySetTests: XCTestCase { func testTypeSafeOrderBySortDescriptors() { let sortDescriptor = NSSortDescriptor(key: "name", ascending: true) - let qs = queryset.orderBy { [$0.name.ascending()] } + let qs = queryset.orderBy { [$0.name.ascending() as SortDescriptor] } XCTAssertTrue(qs.sortDescriptors == [sortDescriptor]) } diff --git a/QueryKitTests/SortDescriptorTests.swift b/Tests/QueryKitTests/SortDescriptorTests.swift similarity index 100% rename from QueryKitTests/SortDescriptorTests.swift rename to Tests/QueryKitTests/SortDescriptorTests.swift From 65db604fa075004be51bdcd390a1df432180d966 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Sun, 1 Mar 2020 14:01:06 +0000 Subject: [PATCH 04/15] chore: switch to GitHub actions --- .github/workflows/main.yaml | 7 +++++++ .travis.yml | 7 ------- README.md | 2 -- 3 files changed, 7 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/main.yaml delete mode 100644 .travis.yml diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml new file mode 100644 index 0000000..9ede81c --- /dev/null +++ b/.github/workflows/main.yaml @@ -0,0 +1,7 @@ +on: push +jobs: + test: + runs-on: macos-latest + steps: + - uses: actions/checkout@v1 + - run: swift test diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index d1e7a88..0000000 --- a/.travis.yml +++ /dev/null @@ -1,7 +0,0 @@ -language: objective-c -osx_image: xcode7.1 -script: - - set -o pipefail - - xcodebuild -project QueryKit.xcodeproj -scheme QueryKit test -sdk macosx | xcpretty -c - - xcodebuild -project QueryKit.xcodeproj -scheme QueryKit test -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO | xcpretty -c - - pod lib lint --allow-warnings --quick diff --git a/README.md b/README.md index c7ca46c..69f0960 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,6 @@ # QueryKit -[![Build Status](http://img.shields.io/travis/QueryKit/QueryKit/master.svg?style=flat)](https://travis-ci.org/QueryKit/QueryKit) - QueryKit, a simple type-safe Core Data query language. ## Usage From 0546e7e970eb0e6234cb9f47b6838d5e6b28d5f2 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Sun, 1 Mar 2020 13:34:03 +0000 Subject: [PATCH 05/15] feat: support KeyPath predicates --- Sources/QueryKit/KeyPath.swift | 86 ++++++++++++++++++ Tests/QueryKitTests/KeyPathTests.swift | 121 +++++++++++++++++++++++++ 2 files changed, 207 insertions(+) create mode 100644 Sources/QueryKit/KeyPath.swift create mode 100644 Tests/QueryKitTests/KeyPathTests.swift diff --git a/Sources/QueryKit/KeyPath.swift b/Sources/QueryKit/KeyPath.swift new file mode 100644 index 0000000..f55733d --- /dev/null +++ b/Sources/QueryKit/KeyPath.swift @@ -0,0 +1,86 @@ +import CoreData + +// MARK: Predicate + +public func == (lhs: KeyPath, rhs: V) -> Predicate { + return Predicate(predicate: lhs == rhs) +} + +public func != (lhs: KeyPath, rhs: V) -> Predicate { + return Predicate(predicate: lhs != rhs) +} + +public func > (lhs: KeyPath, rhs: V) -> Predicate { + return Predicate(predicate: lhs > rhs) +} + +public func >= (lhs: KeyPath, rhs: V) -> Predicate { + return Predicate(predicate: lhs >= rhs) +} + +public func < (lhs: KeyPath, rhs: V) -> Predicate { + return Predicate(predicate: lhs < rhs) +} + +public func <= (lhs: KeyPath, rhs: V) -> Predicate { + return Predicate(predicate: lhs <= rhs) +} + +public func ~= (lhs: KeyPath, rhs: V) -> Predicate { + return Predicate(predicate: lhs ~= rhs) +} + +public func << (lhs: KeyPath, rhs: [V]) -> Predicate { + return Predicate(predicate: lhs << rhs) +} + +public func << (lhs: KeyPath, rhs: Range) -> Predicate { + return Predicate(predicate: lhs << rhs) +} + +// MARK: - NSPredicate + +public func == (lhs: KeyPath, rhs: V) -> NSPredicate { + let attribute = Attribute((lhs as AnyKeyPath)._kvcKeyPathString!) + return attribute == rhs +} + +public func != (lhs: KeyPath, rhs: V) -> NSPredicate { + let attribute = Attribute((lhs as AnyKeyPath)._kvcKeyPathString!) + return attribute != rhs +} + +public func > (lhs: KeyPath, rhs: V) -> NSPredicate { + let attribute = Attribute((lhs as AnyKeyPath)._kvcKeyPathString!) + return attribute > rhs +} + +public func >= (lhs: KeyPath, rhs: V) -> NSPredicate { + let attribute = Attribute((lhs as AnyKeyPath)._kvcKeyPathString!) + return attribute >= rhs +} + +public func < (lhs: KeyPath, rhs: V) -> NSPredicate { + let attribute = Attribute((lhs as AnyKeyPath)._kvcKeyPathString!) + return attribute < rhs +} + +public func <= (lhs: KeyPath, rhs: V) -> NSPredicate { + let attribute = Attribute((lhs as AnyKeyPath)._kvcKeyPathString!) + return attribute <= rhs +} + +public func ~= (lhs: KeyPath, rhs: V) -> NSPredicate { + let attribute = Attribute((lhs as AnyKeyPath)._kvcKeyPathString!) + return attribute ~= rhs +} + +public func << (lhs: KeyPath, rhs: [V]) -> NSPredicate { + let attribute = Attribute((lhs as AnyKeyPath)._kvcKeyPathString!) + return attribute << rhs +} + +public func << (lhs: KeyPath, rhs: Range) -> NSPredicate { + let attribute = Attribute((lhs as AnyKeyPath)._kvcKeyPathString!) + return attribute << rhs +} diff --git a/Tests/QueryKitTests/KeyPathTests.swift b/Tests/QueryKitTests/KeyPathTests.swift new file mode 100644 index 0000000..1bef2f5 --- /dev/null +++ b/Tests/QueryKitTests/KeyPathTests.swift @@ -0,0 +1,121 @@ +import XCTest +@testable import QueryKit + +class KeyPathTests: XCTestCase { + func testEqualityOperator() { + let predicate: Predicate = \User.name == "kyle" + XCTAssertEqual(predicate.predicate, NSPredicate(format:"name == 'kyle'")) + } + + func testEqualityOperatorWithOptional() { + let predicate: Predicate = \User.name == nil + XCTAssertEqual(predicate.predicate, NSPredicate(format:"name == %@", NSNull())) + } + + func testInequalityOperator() { + let predicate: Predicate = \User.name != "kyle" + XCTAssertEqual(predicate.predicate, NSPredicate(format:"name != 'kyle'")) + } + + func testInqqualityOperatorWithOptional() { + let predicate: Predicate = \User.name != nil + XCTAssertEqual(predicate.predicate, NSPredicate(format:"name != %@", NSNull())) + } + + func testGreaterThanOperator() { + let predicate: Predicate = \User.age > 17 + XCTAssertEqual(predicate.predicate, NSPredicate(format:"age > 17")) + } + + func testGreaterThanOrEqualOperator() { + let predicate: Predicate = \User.age >= 18 + XCTAssertEqual(predicate.predicate, NSPredicate(format:"age >= 18")) + } + + func testLessThanOperator() { + let predicate: Predicate = \User.age < 18 + XCTAssertEqual(predicate.predicate, NSPredicate(format:"age < 18")) + } + + func testLessThanOrEqualOperator() { + let predicate: Predicate = \User.age <= 17 + XCTAssertEqual(predicate.predicate, NSPredicate(format:"age <= 17")) + } + + func testLikeOperator() { + let predicate: Predicate = \User.name ~= "k*" + XCTAssertEqual(predicate.predicate, NSPredicate(format:"name LIKE 'k*'")) + } + + func testInOperator() { + let predicate: Predicate = \User.age << [5, 10] + XCTAssertEqual(predicate.predicate, NSPredicate(format:"age IN %@", [5, 10])) + } + + func testBetweenRangeOperator() { + let predicate: Predicate = \User.age << (32 ..< 64) + XCTAssertEqual(predicate.predicate, NSPredicate(format:"age BETWEEN %@", [32, 64])) + } +} + +class KeyPathNSPredicateTests: XCTestCase { + func testEqualityOperator() { + let predicate: NSPredicate = \User.name == "kyle" + XCTAssertEqual(predicate, NSPredicate(format:"name == 'kyle'")) + } + + func testEqualityOperatorWithOptional() { + let predicate: NSPredicate = \User.name == nil + XCTAssertEqual(predicate, NSPredicate(format:"name == %@", NSNull())) + } + + func testInequalityOperator() { + let predicate: NSPredicate = \User.name != "kyle" + XCTAssertEqual(predicate, NSPredicate(format:"name != 'kyle'")) + } + + func testInqqualityOperatorWithOptional() { + let predicate: NSPredicate = \User.name != nil + XCTAssertEqual(predicate, NSPredicate(format:"name != %@", NSNull())) + } + + func testGreaterThanOperator() { + let predicate: NSPredicate = \User.age > 17 + XCTAssertEqual(predicate, NSPredicate(format:"age > 17")) + } + + func testGreaterThanOrEqualOperator() { + let predicate: NSPredicate = \User.age >= 18 + XCTAssertEqual(predicate, NSPredicate(format:"age >= 18")) + } + + func testLessThanOperator() { + let predicate: NSPredicate = \User.age < 18 + XCTAssertEqual(predicate, NSPredicate(format:"age < 18")) + } + + func testLessThanOrEqualOperator() { + let predicate: NSPredicate = \User.age <= 17 + XCTAssertEqual(predicate, NSPredicate(format:"age <= 17")) + } + + func testLikeOperator() { + let predicate: NSPredicate = \User.name ~= "k*" + XCTAssertEqual(predicate, NSPredicate(format:"name LIKE 'k*'")) + } + + func testInOperator() { + let predicate: NSPredicate = \User.age << [5, 10] + XCTAssertEqual(predicate, NSPredicate(format:"age IN %@", [5, 10])) + } + + func testBetweenRangeOperator() { + let predicate: NSPredicate = \User.age << (32 ..< 64) + XCTAssertEqual(predicate, NSPredicate(format:"age BETWEEN %@", [32, 64])) + } +} + +class User: NSManagedObject { + @objc var name: String? + @NSManaged var age: Int +} From a3df08fb2b1c6b39abc0c0533e494ca1f5234c15 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Sun, 1 Mar 2020 13:39:44 +0000 Subject: [PATCH 06/15] feat: support KeyPath ordering --- Sources/QueryKit/QuerySet.swift | 5 +++++ Tests/QueryKitTests/QuerySetTests.swift | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/Sources/QueryKit/QuerySet.swift b/Sources/QueryKit/QuerySet.swift index 8fa51d6..9d057c1 100644 --- a/Sources/QueryKit/QuerySet.swift +++ b/Sources/QueryKit/QuerySet.swift @@ -63,6 +63,11 @@ extension QuerySet { // MARK: Type-safe Sorting + /// Returns a new QuerySet containing objects ordered by the given key path. + public func orderBy(_ keyPath: KeyPath, ascending: Bool) -> QuerySet { + return orderBy(NSSortDescriptor(key: (keyPath as AnyKeyPath)._kvcKeyPathString!, ascending: ascending)) + } + /// Returns a new QuerySet containing objects ordered by the given sort descriptor. public func orderBy(_ closure:((ModelType.Type) -> (SortDescriptor))) -> QuerySet { return orderBy(closure(ModelType.self).sortDescriptor) diff --git a/Tests/QueryKitTests/QuerySetTests.swift b/Tests/QueryKitTests/QuerySetTests.swift index 0653a5a..6a73b2b 100644 --- a/Tests/QueryKitTests/QuerySetTests.swift +++ b/Tests/QueryKitTests/QuerySetTests.swift @@ -44,6 +44,22 @@ class QuerySetTests: XCTestCase { // MARK: Sorting + func testOrderByKeyPathAscending() { + let qs = queryset.orderBy(\.name, ascending: true) + + XCTAssertEqual(qs.sortDescriptors, [ + NSSortDescriptor(key: "name", ascending: true), + ]) + } + + func testOrderByKeyPathDecending() { + let qs = queryset.orderBy(\.name, ascending: false) + + XCTAssertEqual(qs.sortDescriptors, [ + NSSortDescriptor(key: "name", ascending: false), + ]) + } + func testOrderBySortDescriptor() { let sortDescriptor = NSSortDescriptor(key: "name", ascending: true) let qs = queryset.orderBy(sortDescriptor) From 4530948193c0967f3e1c6aeaeba57e0b1834848b Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Sun, 1 Mar 2020 13:44:59 +0000 Subject: [PATCH 07/15] feat: support KeyPath filter/exclude --- Sources/QueryKit/Attribute.swift | 4 ++-- Sources/QueryKit/QuerySet.swift | 10 ++++++++++ Tests/QueryKitTests/QuerySetTests.swift | 10 ++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Sources/QueryKit/Attribute.swift b/Sources/QueryKit/Attribute.swift index 078707b..ecdf487 100644 --- a/Sources/QueryKit/Attribute.swift +++ b/Sources/QueryKit/Attribute.swift @@ -112,11 +112,11 @@ prefix public func ! (left: Attribute) -> NSPredicate { public extension QuerySet { func filter(_ attribute:Attribute) -> QuerySet { - return filter(attribute == true) + return filter((attribute == true) as NSPredicate) } func exclude(_ attribute:Attribute) -> QuerySet { - return filter(attribute == false) + return filter((attribute == false) as NSPredicate) } } diff --git a/Sources/QueryKit/QuerySet.swift b/Sources/QueryKit/QuerySet.swift index 9d057c1..6f85230 100644 --- a/Sources/QueryKit/QuerySet.swift +++ b/Sources/QueryKit/QuerySet.swift @@ -80,6 +80,11 @@ extension QuerySet { // MARK: Filtering + /// Returns a new QuerySet containing objects that match the given predicate. + public func filter(_ predicate: Predicate) -> QuerySet { + return filter(predicate.predicate) + } + /// Returns a new QuerySet containing objects that match the given predicate. public func filter(_ predicate:NSPredicate) -> QuerySet { var futurePredicate = predicate @@ -97,6 +102,11 @@ extension QuerySet { return filter(newPredicate) } + /// Returns a new QuerySet containing objects that exclude the given predicate. + public func exclude(_ predicate: Predicate) -> QuerySet { + return exclude(predicate.predicate) + } + /// Returns a new QuerySet containing objects that exclude the given predicate. public func exclude(_ predicate:NSPredicate) -> QuerySet { let excludePredicate = NSCompoundPredicate(type: NSCompoundPredicate.LogicalType.not, subpredicates: [predicate]) diff --git a/Tests/QueryKitTests/QuerySetTests.swift b/Tests/QueryKitTests/QuerySetTests.swift index 6a73b2b..5ecab25 100644 --- a/Tests/QueryKitTests/QuerySetTests.swift +++ b/Tests/QueryKitTests/QuerySetTests.swift @@ -96,6 +96,11 @@ class QuerySetTests: XCTestCase { // MARK: Filtering + func testFilterKeyPath() { + let qs = queryset.filter(\.name == "Kyle") + XCTAssertEqual(qs.predicate?.description, "name == \"Kyle\"") + } + func testFilterPredicate() { let predicate = NSPredicate(format: "name == Kyle") let qs = queryset.filter(predicate) @@ -136,6 +141,11 @@ class QuerySetTests: XCTestCase { // MARK: Exclusion + func testExcludeKeyPath() { + let qs = queryset.exclude(\.name == "Kyle") + XCTAssertEqual(qs.predicate?.description, "NOT name == \"Kyle\"") + } + func testExcludePredicate() { let predicate = NSPredicate(format: "name == Kyle") let qs = queryset.exclude(predicate) From 7934e49b5c0cfb1382588752f1ea75735a4bd16b Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Sun, 1 Mar 2020 13:57:26 +0000 Subject: [PATCH 08/15] docs: update documentation for KeyPath --- CHANGELOG.md | 15 ++++++++++ README.md | 84 ++++++++++++++++------------------------------------ 2 files changed, 41 insertions(+), 58 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4638af..2fb1ba1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,3 +5,18 @@ ### Breaking * Drops support for Swift 3 and Swift 4. Swift 5 or newer must be used. + +### Enhancements + +* Added support for ordering by Swift KeyPath, for example: + + ```swift + queryset.orderBy(\.createdAt, ascending: true) + ``` + +* Added support for filtering and excluding by Swift KeyPath, for example: + + ```swift + queryset.exclude(\.name == "Kyle") + queryset.filter(\.createdAt > Date()) + ``` diff --git a/README.md b/README.md index 69f0960..2cc9993 100644 --- a/README.md +++ b/README.md @@ -6,29 +6,10 @@ QueryKit, a simple type-safe Core Data query language. ## Usage -To get the most out of QueryKit, and to get full type-safe queries, you may -add extensions for your Core Data models providing properties which describe -your models. You may use [querykit-cli](https://github.com/QueryKit/querykit-cli) -to generate these automatically. - -An extension for our a `Person` model might look as follows: - -```swift -extension User { - static var name:Attribute { return Attribute("name") } - static var age:Attribute { return Attribute("age") } -} -``` - -This provides static properties on our User model which represent each property -on our Core Data model, these may be used to construct predicates and sort -descriptors with compile time safety, without stringly typing them -into your application. - ```swift -let namePredicate = Person.name == "Kyle" -let agePredicate = Person.age > 25 -let ageSortDescriptor = Person.age.descending() +QuerySet(context, "Person") + .orderedBy(.name, ascending: true) + .filter(\.age >= 18) ``` ### QuerySet @@ -40,20 +21,19 @@ results based on the given parameters. #### Retrieving all objects ```swift -let queryset = Person.queryset(context) +let queryset = QuerySet(context, "Person") ``` #### Retrieving specific objects with filters You may filter a QuerySet using the `filter` and `exclude` methods, which -accept a closure passing the model type allowing you to access the -type-safe attributes. +accept a predicate which can be constructed using KeyPath extensions. -The `filter` and `exclude` methods return brand new QuerySet's including your filter. +The `filter` and `exclude` methods return new QuerySet's including your filter. ```swift -queryset.filter { $0.name == "Kyle" } -queryset.exclude { $0.age > 25 } +queryset.filter(\.name == "Kyle") +queryset.exclude(\.age > 25) ``` You may also use standard `NSPredicate` if you want to construct complicated @@ -70,14 +50,13 @@ The result of refining a QuerySet is itself a QuerySet, so it’s possible to chain refinements together. For example: ```swift -queryset.filter { $0.name == "Kyle" } - .exclude { $0.age < 25 } - .filter { $0.isEmployed } +queryset.filter(\.name == "Kyle") + .exclude(\.age < 25) ``` -Each time you refine a QuerySet, you get a brand-new QuerySet that is in -no way bound to the previous QuerySet. Each refinement creates a separate -and distinct QuerySet that may be stored, used and reused. +Each time you refine a QuerySet, you get a new QuerySet instance that is in no +way bound to the previous QuerySet. Each refinement creates a separate and +distinct QuerySet that may be stored, used and reused. #### QuerySets are lazy @@ -88,17 +67,15 @@ QuerySet is *evaluated*. #### Ordering You may order a QuerySet's results by using the `orderBy` function which -accepts a closure passing the model type, and expects a sort descriptor in -return. +accepts a KeyPath. ```swift -queryset.orderBy { $0.name.ascending() } +queryset.orderBy(\.name, ascending: true) ``` You may also pass in an `NSSortDescriptor` if you would rather. ```swift -queryset.orderBy(Person.name.ascending()) queryset.orderBy(NSSortDescriptor(key: "name", ascending: true)) ``` @@ -108,7 +85,7 @@ Using slicing, a QuerySet's results may be limited to a specified range. For example, to get the first 5 items in our QuerySet: ```swift -queryset[0..5] +queryset[0...5] ``` **NOTE**: *Remember, QuerySets are lazily evaluated. Slicing doesn’t evaluate the query.* @@ -158,35 +135,26 @@ count or an error if the operation failed. let deleted = try? queryset.delete() ``` -#### Attribute - -The `Attribute` is a generic structure for creating predicates in a -type-safe manner as shown at the start of the README. - -```swift -let name = Attribute("name") -let age = Attribute("age") -``` - ##### Operators -QueryKit provides custom operator functions allowing you to create predicates. +QueryKit provides KeyPath extensions providing operator functions allowing you +to create predicates. ```swift // Name is equal to Kyle -name == "Kyle" +\Person.name == "Kyle" // Name is either equal to Kyle or Katie -name << ["Kyle", "Katie"] +\.Person.name << ["Kyle", "Katie"] // Age is equal to 27 -age == 27 +\.Person.age == 27 // Age is more than or equal to 25 -age >= 25 +\Person.age >= 25 // Age is within the range 22 to 30. -age << (22...30) +\Person.age << (22...30) ``` The following types of comparisons are supported using Attribute: @@ -210,13 +178,13 @@ QueryKit provides the `!`, `&&` and `||` operators for joining multiple predicat ```swift // Persons name is Kyle or Katie -Person.name == "Kyle" || Person.name == "Katie" +\Person.name == "Kyle" || \Person.name == "Katie" // Persons age is more than 25 and their name is Kyle -Person.age >= 25 && Person.name == "Kyle" +\Person.age >= 25 && \Person.name == "Kyle" // Persons name is not Kyle -!(Person.name == "Kyle") +!(\Person.name == "Kyle") ``` ## Installation From ca46aacab13be927d3a6266ed78c03306a9fc290 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Sun, 1 Mar 2020 14:16:27 +0000 Subject: [PATCH 09/15] chore: deprecate attribute filtering/excluding This is replaced by KeyPath --- Sources/QueryKit/QuerySet.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sources/QueryKit/QuerySet.swift b/Sources/QueryKit/QuerySet.swift index 6f85230..a1603bb 100644 --- a/Sources/QueryKit/QuerySet.swift +++ b/Sources/QueryKit/QuerySet.swift @@ -122,21 +122,25 @@ extension QuerySet { // MARK: Type-safe filtering /// Returns a new QuerySet containing objects that match the given predicate. + @available(*, deprecated, renamed: "filter(_:)", message: "Replaced by KeyPath filtering https://git.io/Jv2v3") public func filter(_ closure:((ModelType.Type) -> (Predicate))) -> QuerySet { return filter(closure(ModelType.self).predicate) } /// Returns a new QuerySet containing objects that exclude the given predicate. + @available(*, deprecated, renamed: "exclude(_:)", message: "Replaced by KeyPath filtering https://git.io/Jv2v3") public func exclude(_ closure:((ModelType.Type) -> (Predicate))) -> QuerySet { return exclude(closure(ModelType.self).predicate) } /// Returns a new QuerySet containing objects that match the given predicatess. + @available(*, deprecated, renamed: "filter(_:)", message: "Replaced by KeyPath filtering https://git.io/Jv2v3") public func filter(_ closures:[((ModelType.Type) -> (Predicate))]) -> QuerySet { return filter(closures.map { $0(ModelType.self).predicate }) } /// Returns a new QuerySet containing objects that exclude the given predicates. + @available(*, deprecated, renamed: "exclude(_:)", message: "Replaced by KeyPath filtering https://git.io/Jv2v3") public func exclude(_ closures:[((ModelType.Type) -> (Predicate))]) -> QuerySet { return exclude(closures.map { $0(ModelType.self).predicate }) } From 815777df8d294447c4cbe946f250aa5fdb1e011d Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Sun, 1 Mar 2020 14:19:24 +0000 Subject: [PATCH 10/15] release: 0.14.0 --- QueryKit.podspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/QueryKit.podspec b/QueryKit.podspec index 26b43ea..9111f55 100644 --- a/QueryKit.podspec +++ b/QueryKit.podspec @@ -1,8 +1,8 @@ Pod::Spec.new do |spec| spec.name = 'QueryKit' - spec.version = '0.13.0' + spec.version = '0.14.0' spec.summary = 'A simple type-safe Core Data query language.' - spec.homepage = 'http://querykit.org/' + spec.homepage = 'https://github.com/QueryKit/QueryKit/' spec.license = { :type => 'BSD', :file => 'LICENSE' } spec.author = { 'Kyle Fuller' => 'kyle@fuller.li' } spec.social_media_url = 'https://twitter.com/QueryKit' From 5316d7b54d197d92a9f5af194454daf773a00fcf Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Tue, 3 Mar 2020 22:17:03 +0000 Subject: [PATCH 11/15] fix: support optional operators --- CHANGELOG.md | 6 ++++++ Sources/QueryKit/Attribute.swift | 5 +---- Tests/QueryKitTests/KeyPathTests.swift | 6 ++++++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fb1ba1..7614781 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## Master +### Bug Fixes + +* Prevents fatal error when handling operators with optional `Date` types. + +## 0.14.0 + ### Breaking * Drops support for Swift 3 and Swift 4. Swift 5 or newer must be used. diff --git a/Sources/QueryKit/Attribute.swift b/Sources/QueryKit/Attribute.swift index ecdf487..a917dec 100644 --- a/Sources/QueryKit/Attribute.swift +++ b/Sources/QueryKit/Attribute.swift @@ -43,10 +43,7 @@ public struct Attribute : Equatable { } } - let value = unsafeBitCast(value, to: Optional.self) - if let value = value { - return NSExpression(forConstantValue: value) - } + return NSExpression(forConstantValue: value) } return NSExpression(forConstantValue: NSNull()) diff --git a/Tests/QueryKitTests/KeyPathTests.swift b/Tests/QueryKitTests/KeyPathTests.swift index 1bef2f5..09d44b8 100644 --- a/Tests/QueryKitTests/KeyPathTests.swift +++ b/Tests/QueryKitTests/KeyPathTests.swift @@ -12,6 +12,11 @@ class KeyPathTests: XCTestCase { XCTAssertEqual(predicate.predicate, NSPredicate(format:"name == %@", NSNull())) } + func testOptionalEqualityOperatorWithOptional() { + let predicate: Predicate = \User.createdAt == nil + XCTAssertEqual(predicate.predicate, NSPredicate(format:"createdAt == %@", NSNull())) + } + func testInequalityOperator() { let predicate: Predicate = \User.name != "kyle" XCTAssertEqual(predicate.predicate, NSPredicate(format:"name != 'kyle'")) @@ -118,4 +123,5 @@ class KeyPathNSPredicateTests: XCTestCase { class User: NSManagedObject { @objc var name: String? @NSManaged var age: Int + @objc var createdAt: Date? } From 4ea1d9ca99edeba6a5ab144d4bfc346468b1eff9 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Mon, 9 Mar 2020 18:40:25 +0000 Subject: [PATCH 12/15] refactor: remove KeyPath dependency on Attribute --- Sources/QueryKit/KeyPath.swift | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/Sources/QueryKit/KeyPath.swift b/Sources/QueryKit/KeyPath.swift index f55733d..8991eaa 100644 --- a/Sources/QueryKit/KeyPath.swift +++ b/Sources/QueryKit/KeyPath.swift @@ -1,5 +1,9 @@ import CoreData +func expression(for keyPath: KeyPath) -> NSExpression { + return NSExpression(forKeyPath: (keyPath as AnyKeyPath)._kvcKeyPathString!) +} + // MARK: Predicate public func == (lhs: KeyPath, rhs: V) -> Predicate { @@ -41,46 +45,37 @@ public func << (lhs: KeyPath, rhs: Range) -> Pr // MARK: - NSPredicate public func == (lhs: KeyPath, rhs: V) -> NSPredicate { - let attribute = Attribute((lhs as AnyKeyPath)._kvcKeyPathString!) - return attribute == rhs + return expression(for: lhs) == NSExpression(forConstantValue: rhs) } public func != (lhs: KeyPath, rhs: V) -> NSPredicate { - let attribute = Attribute((lhs as AnyKeyPath)._kvcKeyPathString!) - return attribute != rhs + return expression(for: lhs) != NSExpression(forConstantValue: rhs) } public func > (lhs: KeyPath, rhs: V) -> NSPredicate { - let attribute = Attribute((lhs as AnyKeyPath)._kvcKeyPathString!) - return attribute > rhs + return expression(for: lhs) > NSExpression(forConstantValue: rhs) } public func >= (lhs: KeyPath, rhs: V) -> NSPredicate { - let attribute = Attribute((lhs as AnyKeyPath)._kvcKeyPathString!) - return attribute >= rhs + return expression(for: lhs) >= NSExpression(forConstantValue: rhs) } public func < (lhs: KeyPath, rhs: V) -> NSPredicate { - let attribute = Attribute((lhs as AnyKeyPath)._kvcKeyPathString!) - return attribute < rhs + return expression(for: lhs) < NSExpression(forConstantValue: rhs) } public func <= (lhs: KeyPath, rhs: V) -> NSPredicate { - let attribute = Attribute((lhs as AnyKeyPath)._kvcKeyPathString!) - return attribute <= rhs + return expression(for: lhs) <= NSExpression(forConstantValue: rhs) } public func ~= (lhs: KeyPath, rhs: V) -> NSPredicate { - let attribute = Attribute((lhs as AnyKeyPath)._kvcKeyPathString!) - return attribute ~= rhs + return expression(for: lhs) ~= NSExpression(forConstantValue: rhs) } public func << (lhs: KeyPath, rhs: [V]) -> NSPredicate { - let attribute = Attribute((lhs as AnyKeyPath)._kvcKeyPathString!) - return attribute << rhs + return expression(for: lhs) << NSExpression(forConstantValue: rhs) } public func << (lhs: KeyPath, rhs: Range) -> NSPredicate { - let attribute = Attribute((lhs as AnyKeyPath)._kvcKeyPathString!) - return attribute << rhs + return expression(for: lhs) << NSExpression(forConstantValue: rhs) } From 9407c92c0089c45a085ac7b112e07b9ef511dc25 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Mon, 9 Mar 2020 18:40:33 +0000 Subject: [PATCH 13/15] release: 0.14.1 --- CHANGELOG.md | 2 +- QueryKit.podspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7614781..8001372 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # QueryKit Changelog -## Master +## 0.14.1 ### Bug Fixes diff --git a/QueryKit.podspec b/QueryKit.podspec index 9111f55..03c48fd 100644 --- a/QueryKit.podspec +++ b/QueryKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'QueryKit' - spec.version = '0.14.0' + spec.version = '0.14.1' spec.summary = 'A simple type-safe Core Data query language.' spec.homepage = 'https://github.com/QueryKit/QueryKit/' spec.license = { :type => 'BSD', :file => 'LICENSE' } From a4b9f07f461050287358f46811ebd3099e1d2629 Mon Sep 17 00:00:00 2001 From: mxgc <62173553+mxgc@users.noreply.github.com> Date: Mon, 25 May 2020 03:18:20 -0700 Subject: [PATCH 14/15] fix: add library product to Package.swift (#57) --- Package.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Package.swift b/Package.swift index d661163..ebd1d10 100644 --- a/Package.swift +++ b/Package.swift @@ -5,6 +5,7 @@ import PackageDescription let package = Package( name: "QueryKit", products: [ + .library(name: "QueryKit", targets: ["QueryKit"]), ], targets: [ .target(name: "QueryKit", dependencies: []), From 6542e1129885173d31cc6206855bd8abb52b446a Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Thu, 10 Jun 2021 18:26:06 +0100 Subject: [PATCH 15/15] perf: optimise queryset exists --- Sources/QueryKit/QuerySet.swift | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Sources/QueryKit/QuerySet.swift b/Sources/QueryKit/QuerySet.swift index a1603bb..c63d7a8 100644 --- a/Sources/QueryKit/QuerySet.swift +++ b/Sources/QueryKit/QuerySet.swift @@ -223,8 +223,11 @@ extension QuerySet { :note: Returns nil if the operation could not be completed. */ public func exists() throws -> Bool { - let result:Int = try count() - return result > 0 + let fetchRequest = self.fetchRequest + fetchRequest.fetchLimit = 1 + + let result = try context.count(for: fetchRequest) + return result != 0 } // MARK: Deletion