├── .gitignore ├── .swiftpm └── xcode │ ├── package.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── swapnilnandgave.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ ├── xcshareddata │ └── xcschemes │ │ └── ODataSwift.xcscheme │ └── xcuserdata │ └── swapnilnandgave.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── Examples └── Example-iOS │ └── ODataSwiftExample │ ├── ODataSwiftExample.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── xcshareddata │ │ └── xcschemes │ │ │ └── ODataSwiftExample.xcscheme │ └── xcuserdata │ │ └── swapnilnandgave.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist │ ├── ODataSwiftExample │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ ├── SceneDelegate.swift │ └── ViewController.swift │ ├── ODataSwiftExampleTests │ ├── Info.plist │ └── ODataSwiftExampleTests.swift │ └── ODataSwiftExampleUITests │ ├── Info.plist │ └── ODataSwiftExampleUITests.swift ├── LICENSE ├── ODataSwift.podspec ├── ODataSwift.xcworkspace ├── contents.xcworkspacedata ├── xcshareddata │ ├── IDEWorkspaceChecks.plist │ └── WorkspaceSettings.xcsettings └── xcuserdata │ └── swapnilnandgave.xcuserdatad │ ├── UserInterfaceState.xcuserstate │ ├── WorkspaceSettings.xcsettings │ └── xcdebugger │ └── Breakpoints_v2.xcbkptlist ├── Package.swift ├── README.md ├── Sources └── ODataSwift │ ├── Count.swift │ ├── DateTime.swift │ ├── Error.swift │ ├── Expand.swift │ ├── Filter.swift │ ├── Funtion.swift │ ├── ODataQueryBuilder.swift │ ├── Order.swift │ ├── QueryConvertible.swift │ ├── QueryOption.swift │ └── Search.swift └── Tests ├── LinuxMain.swift └── ODataSwiftTests ├── ODataSwiftTests.swift └── XCTestManifests.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | 8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 9 | *.xcscmblueprint 10 | *.xccheckout 11 | 12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 13 | build/ 14 | DerivedData/ 15 | *.moved-aside 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | 28 | ## Other 29 | *.moved-aside 30 | *.xcuserstate 31 | 32 | ## App packaging 33 | *.ipa 34 | *.dSYM.zip 35 | *.dSYM 36 | 37 | ## Playgrounds 38 | timeline.xctimeline 39 | playground.xcworkspace 40 | 41 | # Swift Package Manager 42 | # 43 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 44 | # Packages/ 45 | # Package.pins 46 | # Package.resolved 47 | # *.xcodeproj 48 | # 49 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 50 | # hence it is not needed unless you have added a package configuration file to your project 51 | # .swiftpm 52 | 53 | .build/ 54 | 55 | # CocoaPods 56 | # 57 | # We recommend against adding the Pods directory to your .gitignore. However 58 | # you should judge for yourself, the pros and cons are mentioned at: 59 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 60 | # 61 | # Pods/ 62 | # 63 | # Add this line if you want to avoid checking in source code from the Xcode workspace 64 | # *.xcworkspace 65 | 66 | # Carthage 67 | # 68 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 69 | # Carthage/Checkouts 70 | 71 | Carthage/Build/ 72 | 73 | # Accio dependency management 74 | Dependencies/ 75 | .accio/ 76 | 77 | # fastlane 78 | # 79 | # It is recommended to not store the screenshots in the git repo. 80 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 81 | # For more information about the recommended setup visit: 82 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 83 | 84 | fastlane/report.xml 85 | fastlane/Preview.html 86 | fastlane/screenshots/**/*.png 87 | fastlane/test_output 88 | 89 | # Code Injection 90 | # 91 | # After new code Injection tools there's a generated folder /iOSInjectionProject 92 | # https://github.com/johnno1962/injectionforxcode 93 | 94 | iOSInjectionProject/ 95 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/xcuserdata/swapnilnandgave.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developer-celusion/ODataSwift/3d1fb9bfc0ac33a4e662fbb1dd7382489c2fa981/.swiftpm/xcode/package.xcworkspace/xcuserdata/swapnilnandgave.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /.swiftpm/xcode/xcshareddata/xcschemes/ODataSwift.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 67 | 68 | 74 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /.swiftpm/xcode/xcuserdata/swapnilnandgave.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ODataSwift.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | ODataSwift 16 | 17 | primary 18 | 19 | 20 | ODataSwiftTests 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Examples/Example-iOS/ODataSwiftExample/ODataSwiftExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 52; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | B85BED4A23BDF6C4006CD507 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85BED4923BDF6C4006CD507 /* AppDelegate.swift */; }; 11 | B85BED4C23BDF6C4006CD507 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85BED4B23BDF6C4006CD507 /* SceneDelegate.swift */; }; 12 | B85BED4E23BDF6C4006CD507 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85BED4D23BDF6C4006CD507 /* ViewController.swift */; }; 13 | B85BED5123BDF6C4006CD507 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B85BED4F23BDF6C4006CD507 /* Main.storyboard */; }; 14 | B85BED5323BDF6C7006CD507 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B85BED5223BDF6C7006CD507 /* Assets.xcassets */; }; 15 | B85BED5623BDF6C7006CD507 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B85BED5423BDF6C7006CD507 /* LaunchScreen.storyboard */; }; 16 | B85BED6123BDF6C8006CD507 /* ODataSwiftExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85BED6023BDF6C8006CD507 /* ODataSwiftExampleTests.swift */; }; 17 | B85BED6C23BDF6C8006CD507 /* ODataSwiftExampleUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85BED6B23BDF6C8006CD507 /* ODataSwiftExampleUITests.swift */; }; 18 | B85BED7B23BDF724006CD507 /* ODataSwift in Frameworks */ = {isa = PBXBuildFile; productRef = B85BED7A23BDF724006CD507 /* ODataSwift */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXContainerItemProxy section */ 22 | B85BED5D23BDF6C8006CD507 /* PBXContainerItemProxy */ = { 23 | isa = PBXContainerItemProxy; 24 | containerPortal = B85BED3E23BDF6C4006CD507 /* Project object */; 25 | proxyType = 1; 26 | remoteGlobalIDString = B85BED4523BDF6C4006CD507; 27 | remoteInfo = ODataSwiftExample; 28 | }; 29 | B85BED6823BDF6C8006CD507 /* PBXContainerItemProxy */ = { 30 | isa = PBXContainerItemProxy; 31 | containerPortal = B85BED3E23BDF6C4006CD507 /* Project object */; 32 | proxyType = 1; 33 | remoteGlobalIDString = B85BED4523BDF6C4006CD507; 34 | remoteInfo = ODataSwiftExample; 35 | }; 36 | /* End PBXContainerItemProxy section */ 37 | 38 | /* Begin PBXFileReference section */ 39 | B85BED4623BDF6C4006CD507 /* ODataSwiftExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ODataSwiftExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 40 | B85BED4923BDF6C4006CD507 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 41 | B85BED4B23BDF6C4006CD507 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 42 | B85BED4D23BDF6C4006CD507 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 43 | B85BED5023BDF6C4006CD507 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 44 | B85BED5223BDF6C7006CD507 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 45 | B85BED5523BDF6C7006CD507 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 46 | B85BED5723BDF6C7006CD507 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 47 | B85BED5C23BDF6C8006CD507 /* ODataSwiftExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ODataSwiftExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 48 | B85BED6023BDF6C8006CD507 /* ODataSwiftExampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ODataSwiftExampleTests.swift; sourceTree = ""; }; 49 | B85BED6223BDF6C8006CD507 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 50 | B85BED6723BDF6C8006CD507 /* ODataSwiftExampleUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ODataSwiftExampleUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 51 | B85BED6B23BDF6C8006CD507 /* ODataSwiftExampleUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ODataSwiftExampleUITests.swift; sourceTree = ""; }; 52 | B85BED6D23BDF6C8006CD507 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 53 | /* End PBXFileReference section */ 54 | 55 | /* Begin PBXFrameworksBuildPhase section */ 56 | B85BED4323BDF6C4006CD507 /* Frameworks */ = { 57 | isa = PBXFrameworksBuildPhase; 58 | buildActionMask = 2147483647; 59 | files = ( 60 | B85BED7B23BDF724006CD507 /* ODataSwift in Frameworks */, 61 | ); 62 | runOnlyForDeploymentPostprocessing = 0; 63 | }; 64 | B85BED5923BDF6C8006CD507 /* Frameworks */ = { 65 | isa = PBXFrameworksBuildPhase; 66 | buildActionMask = 2147483647; 67 | files = ( 68 | ); 69 | runOnlyForDeploymentPostprocessing = 0; 70 | }; 71 | B85BED6423BDF6C8006CD507 /* Frameworks */ = { 72 | isa = PBXFrameworksBuildPhase; 73 | buildActionMask = 2147483647; 74 | files = ( 75 | ); 76 | runOnlyForDeploymentPostprocessing = 0; 77 | }; 78 | /* End PBXFrameworksBuildPhase section */ 79 | 80 | /* Begin PBXGroup section */ 81 | B85BED3D23BDF6C4006CD507 = { 82 | isa = PBXGroup; 83 | children = ( 84 | B85BED4823BDF6C4006CD507 /* ODataSwiftExample */, 85 | B85BED5F23BDF6C8006CD507 /* ODataSwiftExampleTests */, 86 | B85BED6A23BDF6C8006CD507 /* ODataSwiftExampleUITests */, 87 | B85BED4723BDF6C4006CD507 /* Products */, 88 | B85BED7923BDF724006CD507 /* Frameworks */, 89 | ); 90 | sourceTree = ""; 91 | }; 92 | B85BED4723BDF6C4006CD507 /* Products */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | B85BED4623BDF6C4006CD507 /* ODataSwiftExample.app */, 96 | B85BED5C23BDF6C8006CD507 /* ODataSwiftExampleTests.xctest */, 97 | B85BED6723BDF6C8006CD507 /* ODataSwiftExampleUITests.xctest */, 98 | ); 99 | name = Products; 100 | sourceTree = ""; 101 | }; 102 | B85BED4823BDF6C4006CD507 /* ODataSwiftExample */ = { 103 | isa = PBXGroup; 104 | children = ( 105 | B85BED4923BDF6C4006CD507 /* AppDelegate.swift */, 106 | B85BED4B23BDF6C4006CD507 /* SceneDelegate.swift */, 107 | B85BED4D23BDF6C4006CD507 /* ViewController.swift */, 108 | B85BED4F23BDF6C4006CD507 /* Main.storyboard */, 109 | B85BED5223BDF6C7006CD507 /* Assets.xcassets */, 110 | B85BED5423BDF6C7006CD507 /* LaunchScreen.storyboard */, 111 | B85BED5723BDF6C7006CD507 /* Info.plist */, 112 | ); 113 | path = ODataSwiftExample; 114 | sourceTree = ""; 115 | }; 116 | B85BED5F23BDF6C8006CD507 /* ODataSwiftExampleTests */ = { 117 | isa = PBXGroup; 118 | children = ( 119 | B85BED6023BDF6C8006CD507 /* ODataSwiftExampleTests.swift */, 120 | B85BED6223BDF6C8006CD507 /* Info.plist */, 121 | ); 122 | path = ODataSwiftExampleTests; 123 | sourceTree = ""; 124 | }; 125 | B85BED6A23BDF6C8006CD507 /* ODataSwiftExampleUITests */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | B85BED6B23BDF6C8006CD507 /* ODataSwiftExampleUITests.swift */, 129 | B85BED6D23BDF6C8006CD507 /* Info.plist */, 130 | ); 131 | path = ODataSwiftExampleUITests; 132 | sourceTree = ""; 133 | }; 134 | B85BED7923BDF724006CD507 /* Frameworks */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | ); 138 | name = Frameworks; 139 | sourceTree = ""; 140 | }; 141 | /* End PBXGroup section */ 142 | 143 | /* Begin PBXNativeTarget section */ 144 | B85BED4523BDF6C4006CD507 /* ODataSwiftExample */ = { 145 | isa = PBXNativeTarget; 146 | buildConfigurationList = B85BED7023BDF6C8006CD507 /* Build configuration list for PBXNativeTarget "ODataSwiftExample" */; 147 | buildPhases = ( 148 | B85BED4223BDF6C4006CD507 /* Sources */, 149 | B85BED4323BDF6C4006CD507 /* Frameworks */, 150 | B85BED4423BDF6C4006CD507 /* Resources */, 151 | ); 152 | buildRules = ( 153 | ); 154 | dependencies = ( 155 | ); 156 | name = ODataSwiftExample; 157 | packageProductDependencies = ( 158 | B85BED7A23BDF724006CD507 /* ODataSwift */, 159 | ); 160 | productName = ODataSwiftExample; 161 | productReference = B85BED4623BDF6C4006CD507 /* ODataSwiftExample.app */; 162 | productType = "com.apple.product-type.application"; 163 | }; 164 | B85BED5B23BDF6C8006CD507 /* ODataSwiftExampleTests */ = { 165 | isa = PBXNativeTarget; 166 | buildConfigurationList = B85BED7323BDF6C8006CD507 /* Build configuration list for PBXNativeTarget "ODataSwiftExampleTests" */; 167 | buildPhases = ( 168 | B85BED5823BDF6C8006CD507 /* Sources */, 169 | B85BED5923BDF6C8006CD507 /* Frameworks */, 170 | B85BED5A23BDF6C8006CD507 /* Resources */, 171 | ); 172 | buildRules = ( 173 | ); 174 | dependencies = ( 175 | B85BED5E23BDF6C8006CD507 /* PBXTargetDependency */, 176 | ); 177 | name = ODataSwiftExampleTests; 178 | productName = ODataSwiftExampleTests; 179 | productReference = B85BED5C23BDF6C8006CD507 /* ODataSwiftExampleTests.xctest */; 180 | productType = "com.apple.product-type.bundle.unit-test"; 181 | }; 182 | B85BED6623BDF6C8006CD507 /* ODataSwiftExampleUITests */ = { 183 | isa = PBXNativeTarget; 184 | buildConfigurationList = B85BED7623BDF6C8006CD507 /* Build configuration list for PBXNativeTarget "ODataSwiftExampleUITests" */; 185 | buildPhases = ( 186 | B85BED6323BDF6C8006CD507 /* Sources */, 187 | B85BED6423BDF6C8006CD507 /* Frameworks */, 188 | B85BED6523BDF6C8006CD507 /* Resources */, 189 | ); 190 | buildRules = ( 191 | ); 192 | dependencies = ( 193 | B85BED6923BDF6C8006CD507 /* PBXTargetDependency */, 194 | ); 195 | name = ODataSwiftExampleUITests; 196 | productName = ODataSwiftExampleUITests; 197 | productReference = B85BED6723BDF6C8006CD507 /* ODataSwiftExampleUITests.xctest */; 198 | productType = "com.apple.product-type.bundle.ui-testing"; 199 | }; 200 | /* End PBXNativeTarget section */ 201 | 202 | /* Begin PBXProject section */ 203 | B85BED3E23BDF6C4006CD507 /* Project object */ = { 204 | isa = PBXProject; 205 | attributes = { 206 | LastSwiftUpdateCheck = 1120; 207 | LastUpgradeCheck = 1120; 208 | ORGANIZATIONNAME = "Celusion Technologies"; 209 | TargetAttributes = { 210 | B85BED4523BDF6C4006CD507 = { 211 | CreatedOnToolsVersion = 11.2.1; 212 | }; 213 | B85BED5B23BDF6C8006CD507 = { 214 | CreatedOnToolsVersion = 11.2.1; 215 | TestTargetID = B85BED4523BDF6C4006CD507; 216 | }; 217 | B85BED6623BDF6C8006CD507 = { 218 | CreatedOnToolsVersion = 11.2.1; 219 | TestTargetID = B85BED4523BDF6C4006CD507; 220 | }; 221 | }; 222 | }; 223 | buildConfigurationList = B85BED4123BDF6C4006CD507 /* Build configuration list for PBXProject "ODataSwiftExample" */; 224 | compatibilityVersion = "Xcode 9.3"; 225 | developmentRegion = en; 226 | hasScannedForEncodings = 0; 227 | knownRegions = ( 228 | en, 229 | Base, 230 | ); 231 | mainGroup = B85BED3D23BDF6C4006CD507; 232 | productRefGroup = B85BED4723BDF6C4006CD507 /* Products */; 233 | projectDirPath = ""; 234 | projectRoot = ""; 235 | targets = ( 236 | B85BED4523BDF6C4006CD507 /* ODataSwiftExample */, 237 | B85BED5B23BDF6C8006CD507 /* ODataSwiftExampleTests */, 238 | B85BED6623BDF6C8006CD507 /* ODataSwiftExampleUITests */, 239 | ); 240 | }; 241 | /* End PBXProject section */ 242 | 243 | /* Begin PBXResourcesBuildPhase section */ 244 | B85BED4423BDF6C4006CD507 /* Resources */ = { 245 | isa = PBXResourcesBuildPhase; 246 | buildActionMask = 2147483647; 247 | files = ( 248 | B85BED5623BDF6C7006CD507 /* LaunchScreen.storyboard in Resources */, 249 | B85BED5323BDF6C7006CD507 /* Assets.xcassets in Resources */, 250 | B85BED5123BDF6C4006CD507 /* Main.storyboard in Resources */, 251 | ); 252 | runOnlyForDeploymentPostprocessing = 0; 253 | }; 254 | B85BED5A23BDF6C8006CD507 /* Resources */ = { 255 | isa = PBXResourcesBuildPhase; 256 | buildActionMask = 2147483647; 257 | files = ( 258 | ); 259 | runOnlyForDeploymentPostprocessing = 0; 260 | }; 261 | B85BED6523BDF6C8006CD507 /* Resources */ = { 262 | isa = PBXResourcesBuildPhase; 263 | buildActionMask = 2147483647; 264 | files = ( 265 | ); 266 | runOnlyForDeploymentPostprocessing = 0; 267 | }; 268 | /* End PBXResourcesBuildPhase section */ 269 | 270 | /* Begin PBXSourcesBuildPhase section */ 271 | B85BED4223BDF6C4006CD507 /* Sources */ = { 272 | isa = PBXSourcesBuildPhase; 273 | buildActionMask = 2147483647; 274 | files = ( 275 | B85BED4E23BDF6C4006CD507 /* ViewController.swift in Sources */, 276 | B85BED4A23BDF6C4006CD507 /* AppDelegate.swift in Sources */, 277 | B85BED4C23BDF6C4006CD507 /* SceneDelegate.swift in Sources */, 278 | ); 279 | runOnlyForDeploymentPostprocessing = 0; 280 | }; 281 | B85BED5823BDF6C8006CD507 /* Sources */ = { 282 | isa = PBXSourcesBuildPhase; 283 | buildActionMask = 2147483647; 284 | files = ( 285 | B85BED6123BDF6C8006CD507 /* ODataSwiftExampleTests.swift in Sources */, 286 | ); 287 | runOnlyForDeploymentPostprocessing = 0; 288 | }; 289 | B85BED6323BDF6C8006CD507 /* Sources */ = { 290 | isa = PBXSourcesBuildPhase; 291 | buildActionMask = 2147483647; 292 | files = ( 293 | B85BED6C23BDF6C8006CD507 /* ODataSwiftExampleUITests.swift in Sources */, 294 | ); 295 | runOnlyForDeploymentPostprocessing = 0; 296 | }; 297 | /* End PBXSourcesBuildPhase section */ 298 | 299 | /* Begin PBXTargetDependency section */ 300 | B85BED5E23BDF6C8006CD507 /* PBXTargetDependency */ = { 301 | isa = PBXTargetDependency; 302 | target = B85BED4523BDF6C4006CD507 /* ODataSwiftExample */; 303 | targetProxy = B85BED5D23BDF6C8006CD507 /* PBXContainerItemProxy */; 304 | }; 305 | B85BED6923BDF6C8006CD507 /* PBXTargetDependency */ = { 306 | isa = PBXTargetDependency; 307 | target = B85BED4523BDF6C4006CD507 /* ODataSwiftExample */; 308 | targetProxy = B85BED6823BDF6C8006CD507 /* PBXContainerItemProxy */; 309 | }; 310 | /* End PBXTargetDependency section */ 311 | 312 | /* Begin PBXVariantGroup section */ 313 | B85BED4F23BDF6C4006CD507 /* Main.storyboard */ = { 314 | isa = PBXVariantGroup; 315 | children = ( 316 | B85BED5023BDF6C4006CD507 /* Base */, 317 | ); 318 | name = Main.storyboard; 319 | sourceTree = ""; 320 | }; 321 | B85BED5423BDF6C7006CD507 /* LaunchScreen.storyboard */ = { 322 | isa = PBXVariantGroup; 323 | children = ( 324 | B85BED5523BDF6C7006CD507 /* Base */, 325 | ); 326 | name = LaunchScreen.storyboard; 327 | sourceTree = ""; 328 | }; 329 | /* End PBXVariantGroup section */ 330 | 331 | /* Begin XCBuildConfiguration section */ 332 | B85BED6E23BDF6C8006CD507 /* Debug */ = { 333 | isa = XCBuildConfiguration; 334 | buildSettings = { 335 | ALWAYS_SEARCH_USER_PATHS = NO; 336 | CLANG_ANALYZER_NONNULL = YES; 337 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 338 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 339 | CLANG_CXX_LIBRARY = "libc++"; 340 | CLANG_ENABLE_MODULES = YES; 341 | CLANG_ENABLE_OBJC_ARC = YES; 342 | CLANG_ENABLE_OBJC_WEAK = YES; 343 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 344 | CLANG_WARN_BOOL_CONVERSION = YES; 345 | CLANG_WARN_COMMA = YES; 346 | CLANG_WARN_CONSTANT_CONVERSION = YES; 347 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 348 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 349 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 350 | CLANG_WARN_EMPTY_BODY = YES; 351 | CLANG_WARN_ENUM_CONVERSION = YES; 352 | CLANG_WARN_INFINITE_RECURSION = YES; 353 | CLANG_WARN_INT_CONVERSION = YES; 354 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 355 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 356 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 357 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 358 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 359 | CLANG_WARN_STRICT_PROTOTYPES = YES; 360 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 361 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 362 | CLANG_WARN_UNREACHABLE_CODE = YES; 363 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 364 | COPY_PHASE_STRIP = NO; 365 | DEBUG_INFORMATION_FORMAT = dwarf; 366 | ENABLE_STRICT_OBJC_MSGSEND = YES; 367 | ENABLE_TESTABILITY = YES; 368 | GCC_C_LANGUAGE_STANDARD = gnu11; 369 | GCC_DYNAMIC_NO_PIC = NO; 370 | GCC_NO_COMMON_BLOCKS = YES; 371 | GCC_OPTIMIZATION_LEVEL = 0; 372 | GCC_PREPROCESSOR_DEFINITIONS = ( 373 | "DEBUG=1", 374 | "$(inherited)", 375 | ); 376 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 377 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 378 | GCC_WARN_UNDECLARED_SELECTOR = YES; 379 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 380 | GCC_WARN_UNUSED_FUNCTION = YES; 381 | GCC_WARN_UNUSED_VARIABLE = YES; 382 | IPHONEOS_DEPLOYMENT_TARGET = 13.2; 383 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 384 | MTL_FAST_MATH = YES; 385 | ONLY_ACTIVE_ARCH = YES; 386 | SDKROOT = iphoneos; 387 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 388 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 389 | }; 390 | name = Debug; 391 | }; 392 | B85BED6F23BDF6C8006CD507 /* Release */ = { 393 | isa = XCBuildConfiguration; 394 | buildSettings = { 395 | ALWAYS_SEARCH_USER_PATHS = NO; 396 | CLANG_ANALYZER_NONNULL = YES; 397 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 398 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 399 | CLANG_CXX_LIBRARY = "libc++"; 400 | CLANG_ENABLE_MODULES = YES; 401 | CLANG_ENABLE_OBJC_ARC = YES; 402 | CLANG_ENABLE_OBJC_WEAK = YES; 403 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 404 | CLANG_WARN_BOOL_CONVERSION = YES; 405 | CLANG_WARN_COMMA = YES; 406 | CLANG_WARN_CONSTANT_CONVERSION = YES; 407 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 408 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 409 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 410 | CLANG_WARN_EMPTY_BODY = YES; 411 | CLANG_WARN_ENUM_CONVERSION = YES; 412 | CLANG_WARN_INFINITE_RECURSION = YES; 413 | CLANG_WARN_INT_CONVERSION = YES; 414 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 415 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 416 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 417 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 418 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 419 | CLANG_WARN_STRICT_PROTOTYPES = YES; 420 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 421 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 422 | CLANG_WARN_UNREACHABLE_CODE = YES; 423 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 424 | COPY_PHASE_STRIP = NO; 425 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 426 | ENABLE_NS_ASSERTIONS = NO; 427 | ENABLE_STRICT_OBJC_MSGSEND = YES; 428 | GCC_C_LANGUAGE_STANDARD = gnu11; 429 | GCC_NO_COMMON_BLOCKS = YES; 430 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 431 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 432 | GCC_WARN_UNDECLARED_SELECTOR = YES; 433 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 434 | GCC_WARN_UNUSED_FUNCTION = YES; 435 | GCC_WARN_UNUSED_VARIABLE = YES; 436 | IPHONEOS_DEPLOYMENT_TARGET = 13.2; 437 | MTL_ENABLE_DEBUG_INFO = NO; 438 | MTL_FAST_MATH = YES; 439 | SDKROOT = iphoneos; 440 | SWIFT_COMPILATION_MODE = wholemodule; 441 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 442 | VALIDATE_PRODUCT = YES; 443 | }; 444 | name = Release; 445 | }; 446 | B85BED7123BDF6C8006CD507 /* Debug */ = { 447 | isa = XCBuildConfiguration; 448 | buildSettings = { 449 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 450 | CODE_SIGN_STYLE = Automatic; 451 | INFOPLIST_FILE = ODataSwiftExample/Info.plist; 452 | LD_RUNPATH_SEARCH_PATHS = ( 453 | "$(inherited)", 454 | "@executable_path/Frameworks", 455 | ); 456 | MARKETING_VERSION = 1.0.0; 457 | PRODUCT_BUNDLE_IDENTIFIER = com.celusion.ODataSwiftExample; 458 | PRODUCT_NAME = "$(TARGET_NAME)"; 459 | SWIFT_VERSION = 5.0; 460 | TARGETED_DEVICE_FAMILY = "1,2"; 461 | }; 462 | name = Debug; 463 | }; 464 | B85BED7223BDF6C8006CD507 /* Release */ = { 465 | isa = XCBuildConfiguration; 466 | buildSettings = { 467 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 468 | CODE_SIGN_STYLE = Automatic; 469 | INFOPLIST_FILE = ODataSwiftExample/Info.plist; 470 | LD_RUNPATH_SEARCH_PATHS = ( 471 | "$(inherited)", 472 | "@executable_path/Frameworks", 473 | ); 474 | MARKETING_VERSION = 1.0.0; 475 | PRODUCT_BUNDLE_IDENTIFIER = com.celusion.ODataSwiftExample; 476 | PRODUCT_NAME = "$(TARGET_NAME)"; 477 | SWIFT_VERSION = 5.0; 478 | TARGETED_DEVICE_FAMILY = "1,2"; 479 | }; 480 | name = Release; 481 | }; 482 | B85BED7423BDF6C8006CD507 /* Debug */ = { 483 | isa = XCBuildConfiguration; 484 | buildSettings = { 485 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 486 | BUNDLE_LOADER = "$(TEST_HOST)"; 487 | CODE_SIGN_STYLE = Automatic; 488 | INFOPLIST_FILE = ODataSwiftExampleTests/Info.plist; 489 | IPHONEOS_DEPLOYMENT_TARGET = 13.2; 490 | LD_RUNPATH_SEARCH_PATHS = ( 491 | "$(inherited)", 492 | "@executable_path/Frameworks", 493 | "@loader_path/Frameworks", 494 | ); 495 | PRODUCT_BUNDLE_IDENTIFIER = com.celusion.ODataSwiftExampleTests; 496 | PRODUCT_NAME = "$(TARGET_NAME)"; 497 | SWIFT_VERSION = 5.0; 498 | TARGETED_DEVICE_FAMILY = "1,2"; 499 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ODataSwiftExample.app/ODataSwiftExample"; 500 | }; 501 | name = Debug; 502 | }; 503 | B85BED7523BDF6C8006CD507 /* Release */ = { 504 | isa = XCBuildConfiguration; 505 | buildSettings = { 506 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 507 | BUNDLE_LOADER = "$(TEST_HOST)"; 508 | CODE_SIGN_STYLE = Automatic; 509 | INFOPLIST_FILE = ODataSwiftExampleTests/Info.plist; 510 | IPHONEOS_DEPLOYMENT_TARGET = 13.2; 511 | LD_RUNPATH_SEARCH_PATHS = ( 512 | "$(inherited)", 513 | "@executable_path/Frameworks", 514 | "@loader_path/Frameworks", 515 | ); 516 | PRODUCT_BUNDLE_IDENTIFIER = com.celusion.ODataSwiftExampleTests; 517 | PRODUCT_NAME = "$(TARGET_NAME)"; 518 | SWIFT_VERSION = 5.0; 519 | TARGETED_DEVICE_FAMILY = "1,2"; 520 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ODataSwiftExample.app/ODataSwiftExample"; 521 | }; 522 | name = Release; 523 | }; 524 | B85BED7723BDF6C8006CD507 /* Debug */ = { 525 | isa = XCBuildConfiguration; 526 | buildSettings = { 527 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 528 | CODE_SIGN_STYLE = Automatic; 529 | INFOPLIST_FILE = ODataSwiftExampleUITests/Info.plist; 530 | LD_RUNPATH_SEARCH_PATHS = ( 531 | "$(inherited)", 532 | "@executable_path/Frameworks", 533 | "@loader_path/Frameworks", 534 | ); 535 | PRODUCT_BUNDLE_IDENTIFIER = com.celusion.ODataSwiftExampleUITests; 536 | PRODUCT_NAME = "$(TARGET_NAME)"; 537 | SWIFT_VERSION = 5.0; 538 | TARGETED_DEVICE_FAMILY = "1,2"; 539 | TEST_TARGET_NAME = ODataSwiftExample; 540 | }; 541 | name = Debug; 542 | }; 543 | B85BED7823BDF6C8006CD507 /* Release */ = { 544 | isa = XCBuildConfiguration; 545 | buildSettings = { 546 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 547 | CODE_SIGN_STYLE = Automatic; 548 | INFOPLIST_FILE = ODataSwiftExampleUITests/Info.plist; 549 | LD_RUNPATH_SEARCH_PATHS = ( 550 | "$(inherited)", 551 | "@executable_path/Frameworks", 552 | "@loader_path/Frameworks", 553 | ); 554 | PRODUCT_BUNDLE_IDENTIFIER = com.celusion.ODataSwiftExampleUITests; 555 | PRODUCT_NAME = "$(TARGET_NAME)"; 556 | SWIFT_VERSION = 5.0; 557 | TARGETED_DEVICE_FAMILY = "1,2"; 558 | TEST_TARGET_NAME = ODataSwiftExample; 559 | }; 560 | name = Release; 561 | }; 562 | /* End XCBuildConfiguration section */ 563 | 564 | /* Begin XCConfigurationList section */ 565 | B85BED4123BDF6C4006CD507 /* Build configuration list for PBXProject "ODataSwiftExample" */ = { 566 | isa = XCConfigurationList; 567 | buildConfigurations = ( 568 | B85BED6E23BDF6C8006CD507 /* Debug */, 569 | B85BED6F23BDF6C8006CD507 /* Release */, 570 | ); 571 | defaultConfigurationIsVisible = 0; 572 | defaultConfigurationName = Release; 573 | }; 574 | B85BED7023BDF6C8006CD507 /* Build configuration list for PBXNativeTarget "ODataSwiftExample" */ = { 575 | isa = XCConfigurationList; 576 | buildConfigurations = ( 577 | B85BED7123BDF6C8006CD507 /* Debug */, 578 | B85BED7223BDF6C8006CD507 /* Release */, 579 | ); 580 | defaultConfigurationIsVisible = 0; 581 | defaultConfigurationName = Release; 582 | }; 583 | B85BED7323BDF6C8006CD507 /* Build configuration list for PBXNativeTarget "ODataSwiftExampleTests" */ = { 584 | isa = XCConfigurationList; 585 | buildConfigurations = ( 586 | B85BED7423BDF6C8006CD507 /* Debug */, 587 | B85BED7523BDF6C8006CD507 /* Release */, 588 | ); 589 | defaultConfigurationIsVisible = 0; 590 | defaultConfigurationName = Release; 591 | }; 592 | B85BED7623BDF6C8006CD507 /* Build configuration list for PBXNativeTarget "ODataSwiftExampleUITests" */ = { 593 | isa = XCConfigurationList; 594 | buildConfigurations = ( 595 | B85BED7723BDF6C8006CD507 /* Debug */, 596 | B85BED7823BDF6C8006CD507 /* Release */, 597 | ); 598 | defaultConfigurationIsVisible = 0; 599 | defaultConfigurationName = Release; 600 | }; 601 | /* End XCConfigurationList section */ 602 | 603 | /* Begin XCSwiftPackageProductDependency section */ 604 | B85BED7A23BDF724006CD507 /* ODataSwift */ = { 605 | isa = XCSwiftPackageProductDependency; 606 | productName = ODataSwift; 607 | }; 608 | /* End XCSwiftPackageProductDependency section */ 609 | }; 610 | rootObject = B85BED3E23BDF6C4006CD507 /* Project object */; 611 | } 612 | -------------------------------------------------------------------------------- /Examples/Example-iOS/ODataSwiftExample/ODataSwiftExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/Example-iOS/ODataSwiftExample/ODataSwiftExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Examples/Example-iOS/ODataSwiftExample/ODataSwiftExample.xcodeproj/xcshareddata/xcschemes/ODataSwiftExample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 63 | 65 | 71 | 72 | 73 | 74 | 80 | 82 | 88 | 89 | 90 | 91 | 93 | 94 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /Examples/Example-iOS/ODataSwiftExample/ODataSwiftExample.xcodeproj/xcuserdata/swapnilnandgave.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ODataSwiftExample.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 1 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | B85BED4523BDF6C4006CD507 16 | 17 | primary 18 | 19 | 20 | B85BED5B23BDF6C8006CD507 21 | 22 | primary 23 | 24 | 25 | B85BED6623BDF6C8006CD507 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Examples/Example-iOS/ODataSwiftExample/ODataSwiftExample/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // ODataSwiftExample 4 | // 5 | // Created by Swapnil Nandgave on 02/01/20. 6 | // Copyright © 2020 Celusion Technologies. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | 15 | 16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 17 | // Override point for customization after application launch. 18 | return true 19 | } 20 | 21 | // MARK: UISceneSession Lifecycle 22 | 23 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 24 | // Called when a new scene session is being created. 25 | // Use this method to select a configuration to create the new scene with. 26 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 27 | } 28 | 29 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 30 | // Called when the user discards a scene session. 31 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 32 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 33 | } 34 | 35 | 36 | } 37 | 38 | -------------------------------------------------------------------------------- /Examples/Example-iOS/ODataSwiftExample/ODataSwiftExample/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /Examples/Example-iOS/ODataSwiftExample/ODataSwiftExample/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Examples/Example-iOS/ODataSwiftExample/ODataSwiftExample/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Examples/Example-iOS/ODataSwiftExample/ODataSwiftExample/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 29 | 37 | 45 | 54 | 62 | 70 | 78 | 86 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /Examples/Example-iOS/ODataSwiftExample/ODataSwiftExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIApplicationSceneManifest 24 | 25 | UIApplicationSupportsMultipleScenes 26 | 27 | UISceneConfigurations 28 | 29 | UIWindowSceneSessionRoleApplication 30 | 31 | 32 | UISceneConfigurationName 33 | Default Configuration 34 | UISceneDelegateClassName 35 | $(PRODUCT_MODULE_NAME).SceneDelegate 36 | UISceneStoryboardFile 37 | Main 38 | 39 | 40 | 41 | 42 | UILaunchStoryboardName 43 | LaunchScreen 44 | UIMainStoryboardFile 45 | Main 46 | UIRequiredDeviceCapabilities 47 | 48 | armv7 49 | 50 | UISupportedInterfaceOrientations 51 | 52 | UIInterfaceOrientationPortrait 53 | UIInterfaceOrientationLandscapeLeft 54 | UIInterfaceOrientationLandscapeRight 55 | 56 | UISupportedInterfaceOrientations~ipad 57 | 58 | UIInterfaceOrientationPortrait 59 | UIInterfaceOrientationPortraitUpsideDown 60 | UIInterfaceOrientationLandscapeLeft 61 | UIInterfaceOrientationLandscapeRight 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /Examples/Example-iOS/ODataSwiftExample/ODataSwiftExample/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // ODataSwiftExample 4 | // 5 | // Created by Swapnil Nandgave on 02/01/20. 6 | // Copyright © 2020 Celusion Technologies. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 12 | 13 | var window: UIWindow? 14 | 15 | 16 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 17 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 18 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 19 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 20 | guard let _ = (scene as? UIWindowScene) else { return } 21 | } 22 | 23 | func sceneDidDisconnect(_ scene: UIScene) { 24 | // Called as the scene is being released by the system. 25 | // This occurs shortly after the scene enters the background, or when its session is discarded. 26 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 27 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). 28 | } 29 | 30 | func sceneDidBecomeActive(_ scene: UIScene) { 31 | // Called when the scene has moved from an inactive state to an active state. 32 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 33 | } 34 | 35 | func sceneWillResignActive(_ scene: UIScene) { 36 | // Called when the scene will move from an active state to an inactive state. 37 | // This may occur due to temporary interruptions (ex. an incoming phone call). 38 | } 39 | 40 | func sceneWillEnterForeground(_ scene: UIScene) { 41 | // Called as the scene transitions from the background to the foreground. 42 | // Use this method to undo the changes made on entering the background. 43 | } 44 | 45 | func sceneDidEnterBackground(_ scene: UIScene) { 46 | // Called as the scene transitions from the foreground to the background. 47 | // Use this method to save data, release shared resources, and store enough scene-specific state information 48 | // to restore the scene back to its current state. 49 | } 50 | 51 | 52 | } 53 | 54 | -------------------------------------------------------------------------------- /Examples/Example-iOS/ODataSwiftExample/ODataSwiftExample/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // ODataSwiftExample 4 | // 5 | // Created by Swapnil Nandgave on 02/01/20. 6 | // Copyright © 2020 Celusion Technologies. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import ODataSwift 11 | 12 | class ViewController: UIViewController { 13 | 14 | @IBOutlet weak var labelGenQuery: UILabel! 15 | 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | // Do any additional setup after loading the view. 19 | labelGenQuery.text = "" 20 | ODataQueryBuilder.configure(url: "https://services.odata.org/V4") 21 | } 22 | 23 | @IBAction func selectDidPressed(_ sender: Any) { 24 | let str = ODataQueryBuilder().entity("Airports").selects(["Name","IcaoCode"]).build() 25 | labelGenQuery.text = str 26 | } 27 | 28 | @IBAction func filterDidPressed(_ sender: Any) { 29 | let filter = FilterExp("FirstName").eq().value("Scott").and([FilterExp("FirstName").eq().value("Scott")]) 30 | var str = ODataQueryBuilder().entity("People").filter(filter).build() 31 | str += "\n" + ODataQueryBuilder().entity("People").filter(FilterExp("username").contains().value("7")).build() 32 | labelGenQuery.text = str 33 | } 34 | 35 | @IBAction func expandDidPressed(_ sender: Any) { 36 | let filter = FilterExp("FirstName").eq().value("Scott").and([FilterExp("FirstName").eq().value("Scott")]) 37 | let expand = Expand("Trips").filter(filter) 38 | let str = ODataQueryBuilder().entity("People").expand(expand).build() 39 | labelGenQuery.text = str 40 | } 41 | 42 | @IBAction func orderDidPressed(_ sender: Any) { 43 | let order = Order("EndsAt", orderType: .desc) 44 | let str = ODataQueryBuilder().entity("People").id("scottketchum", "Trips").order(order).build() 45 | labelGenQuery.text = str 46 | } 47 | 48 | @IBAction func topDidPressed(_ sender: Any) { 49 | let str = ODataQueryBuilder().entity("People").top(2).build() 50 | labelGenQuery.text = str 51 | } 52 | 53 | @IBAction func skipDidPressed(_ sender: Any) { 54 | let str = ODataQueryBuilder().entity("People").skip(18).build() 55 | labelGenQuery.text = str 56 | } 57 | 58 | @IBAction func countDidPressed(_ sender: Any) { 59 | var str = "Count Only: " + ODataQueryBuilder().entity("People").onlyCount().build() 60 | str += "\nWith Count: " + ODataQueryBuilder().entity("People").withCount().build() 61 | str += "\nInline Count: " + ODataQueryBuilder().entity("People").inlineCount("Name").build() 62 | labelGenQuery.text = str 63 | } 64 | 65 | @IBAction func searchDidPressed(_ sender: Any) { 66 | let str = ODataQueryBuilder().entity("People").search(Search("Name")).build() 67 | labelGenQuery.text = str 68 | } 69 | 70 | @IBAction func funcDidPressed(_ sender: Any) { 71 | var str = ODataQueryBuilder().entity("People").filter(FilterExp(PropertyFunc("name", Function.length)).eq().value(30)).build() 72 | str += "\n" + ODataQueryBuilder().entity("People").filter(FilterExp(PropertyFunc("designation", .tolower)).eq().value("director")).build() 73 | str += "\n" + ODataQueryBuilder().entity("People").filter(FilterExp(PropertyFunc("designation", .substring).value(1)).eq().value("di")).build() 74 | str += "\n" + ODataQueryBuilder().entity("People").filter(FilterExp(PropertyFunc("CreatedOn", .year)).eq().value(2018)).build() 75 | str += "\n" + ODataQueryBuilder().entity("People").filter(FilterExp("CreatedOn").lt().date(DateTime.now)).build() 76 | labelGenQuery.text = str 77 | } 78 | 79 | } 80 | 81 | -------------------------------------------------------------------------------- /Examples/Example-iOS/ODataSwiftExample/ODataSwiftExampleTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Examples/Example-iOS/ODataSwiftExample/ODataSwiftExampleTests/ODataSwiftExampleTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ODataSwiftExampleTests.swift 3 | // ODataSwiftExampleTests 4 | // 5 | // Created by Swapnil Nandgave on 02/01/20. 6 | // Copyright © 2020 Celusion Technologies. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import ODataSwiftExample 11 | 12 | class ODataSwiftExampleTests: XCTestCase { 13 | 14 | override func setUp() { 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | } 17 | 18 | override func tearDown() { 19 | // Put teardown code here. This method is called after the invocation of each test method in the class. 20 | } 21 | 22 | func testExample() { 23 | // This is an example of a functional test case. 24 | // Use XCTAssert and related functions to verify your tests produce the correct results. 25 | } 26 | 27 | func testPerformanceExample() { 28 | // This is an example of a performance test case. 29 | self.measure { 30 | // Put the code you want to measure the time of here. 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /Examples/Example-iOS/ODataSwiftExample/ODataSwiftExampleUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Examples/Example-iOS/ODataSwiftExample/ODataSwiftExampleUITests/ODataSwiftExampleUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ODataSwiftExampleUITests.swift 3 | // ODataSwiftExampleUITests 4 | // 5 | // Created by Swapnil Nandgave on 02/01/20. 6 | // Copyright © 2020 Celusion Technologies. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class ODataSwiftExampleUITests: XCTestCase { 12 | 13 | override func setUp() { 14 | // Put setup code here. This method is called before the invocation of each test method in the class. 15 | 16 | // In UI tests it is usually best to stop immediately when a failure occurs. 17 | continueAfterFailure = false 18 | 19 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 20 | } 21 | 22 | override func tearDown() { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | } 25 | 26 | func testExample() { 27 | // UI tests must launch the application that they test. 28 | let app = XCUIApplication() 29 | app.launch() 30 | 31 | // Use recording to get started writing UI tests. 32 | // Use XCTAssert and related functions to verify your tests produce the correct results. 33 | } 34 | 35 | func testLaunchPerformance() { 36 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) { 37 | // This measures how long it takes to launch your application. 38 | measure(metrics: [XCTOSSignpostMetric.applicationLaunch]) { 39 | XCUIApplication().launch() 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Celusion 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ODataSwift.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod lib lint ODataSwift.podspec' to ensure this is a 3 | # valid spec before submitting. 4 | # 5 | # Any lines starting with a # are optional, but their use is encouraged 6 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | s.name = 'ODataSwift' 11 | s.version = '1.0.1' 12 | s.summary = 'The utility package for OData Client in Swift' 13 | 14 | # This description is used to generate tags and improve search results. 15 | # * Think: What does it do? Why did you write it? What is the focus? 16 | # * Try to keep it short, snappy and to the point. 17 | # * Write the description between the DESC delimiters below. 18 | # * Finally, don't worry about the indent, CocoaPods strips it! 19 | 20 | s.description = <<-DESC 21 | ODataSwift is simple utility swift wrapper to generate OData Query V4 that works on iOS and OS X. Makes using ODataSwift builder pattern APIs extremely easy and much more palatable to use in Swift 22 | DESC 23 | 24 | s.homepage = 'https://github.com/developer-celusion/ODataSwift' 25 | # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2' 26 | s.license = { :type => 'MIT', :file => 'LICENSE' } 27 | s.author = { 'developer@celusion.com' => 'developer@celusion.com' } 28 | s.source = { :git => 'https://github.com/developer-celusion/ODataSwift.git', :tag => s.version.to_s } 29 | # s.social_media_url = 'https://twitter.com/' 30 | 31 | s.ios.deployment_target = '9.0' 32 | 33 | s.source_files = 'Sources/ODataSwift/**/*' 34 | 35 | # s.resource_bundles = { 36 | # 'ODataSwift' => ['ODataSwift/Assets/*.png'] 37 | # } 38 | 39 | # s.public_header_files = 'Pod/Classes/**/*.h' 40 | # s.frameworks = 'UIKit', 'MapKit' 41 | # s.dependency 'AFNetworking', '~> 2.3' 42 | # s.dependency 'Alamofire' 43 | end 44 | -------------------------------------------------------------------------------- /ODataSwift.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ODataSwift.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ODataSwift.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ODataSwift.xcworkspace/xcuserdata/swapnilnandgave.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/developer-celusion/ODataSwift/3d1fb9bfc0ac33a4e662fbb1dd7382489c2fa981/ODataSwift.xcworkspace/xcuserdata/swapnilnandgave.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /ODataSwift.xcworkspace/xcuserdata/swapnilnandgave.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildLocationStyle 6 | UseAppPreferences 7 | CustomBuildLocationType 8 | RelativeToDerivedData 9 | DerivedDataLocationStyle 10 | Default 11 | IssueFilterStyle 12 | ShowActiveSchemeOnly 13 | LiveSourceIssuesEnabled 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /ODataSwift.xcworkspace/xcuserdata/swapnilnandgave.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.1 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "ODataSwift", 8 | platforms: [.macOS(.v10_12), 9 | .iOS(.v10), 10 | .tvOS(.v10), 11 | .watchOS(.v3)], 12 | products: [ 13 | // Products define the executables and libraries produced by a package, and make them visible to other packages. 14 | .library( 15 | name: "ODataSwift", 16 | targets: ["ODataSwift"]), 17 | ], 18 | dependencies: [ 19 | // Dependencies declare other packages that this package depends on. 20 | // .package(url: /* package url */, from: "1.0.0"), 21 | ], 22 | targets: [ 23 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 24 | // Targets can depend on other targets in this package, and on products in packages which this package depends on. 25 | .target( 26 | name: "ODataSwift", 27 | dependencies: []), 28 | .testTarget( 29 | name: "ODataSwiftTests", 30 | dependencies: ["ODataSwift"]), 31 | ], 32 | swiftLanguageVersions: [.v5] 33 | ) 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ODataSwift 2 | 3 | ODataSwift is simple utility swift wrapper to generate OData Query V4 that works on iOS and OS X. Makes using ODataSwift builder pattern APIs extremely easy 4 | and much more palatable to use in Swift 5 | 6 | ## :bulb: Features 7 | 8 | - Used builder pattern to generate query 9 | - Support $select, $expand, $filter 10 | - Support odata pagination like $top, $skip 11 | - Support unbound and bound functions 12 | - Support almost all predicates like eq, lt, gt 13 | - Support date time funtions like now() 14 | 15 | ## :book: Usage 16 | 17 | ### :key: Basics 18 | 19 | #### Setting OData URL 20 | ```swift 21 | ODataQueryBuilder.configure(url: "https://services.odata.org/V4") 22 | ``` 23 | 24 | ### :key: Querying Data 25 | 26 | #### $filter 27 | The `$filter` system query option allows clients to filter a collection of resources that are addressed by a request URL 28 | ```swift 29 | let filter = FilterExp("FirstName").eq().value("Scott").and([FilterExp("FirstName").eq().value("Scott")]) 30 | print(ODataQueryBuilder().entity("People").filter(filter).build()) 31 | ``` 32 | #### $orderby 33 | The `$orderby` system query option allows clients to request resources in either ascending order using asc or descending order using desc 34 | ```swift 35 | let order = Order("EndsAt", orderType: .desc) 36 | print(ODataQueryBuilder().entity("People").order(order).build()) 37 | ``` 38 | #### $top 39 | The `$top` system query option requests the number of items in the queried collection to be included in the result 40 | ```swift 41 | print(ODataQueryBuilder().entity("People").top(2).build()) 42 | ``` 43 | #### $skip 44 | The `$skip` query option requests the number of items in the queried collection that are to be skipped and not included in the result 45 | ```swift 46 | print(ODataQueryBuilder().entity("People").skip(18).build()) 47 | ``` 48 | #### $count 49 | The `$count` system query option allows clients to request a count of the matching resources included with the resources in the response 50 | It is available in three as per odata request `.onlyCount()` `.withCount()` `inlineCount(property)` 51 | ```swift 52 | print(ODataQueryBuilder().entity("People").withCount().build()) 53 | ``` 54 | #### $expand 55 | The `$expand` system query option specifies the related resources to be included in line with retrieved resources along with `$select`, `$filter` like system query options 56 | ```swift 57 | let filter = FilterExp("FirstName").eq().value("Scott").and([FilterExp("FirstName").eq().value("Scott")]) 58 | let expand = Expand("Trips").filter(filter) 59 | print(ODataQueryBuilder().entity("People").expand(expand).build()) 60 | ``` 61 | #### $select 62 | The `$select` system query option allows the clients to requests a limited set of properties for each entity 63 | ```swift 64 | print(ODataQueryBuilder().entity("Airports").selects(["Name","IcaoCode"]).build()) 65 | ``` 66 | #### $search 67 | The `$search` system query option restricts the result to include only those entities matching the specified search expression 68 | ```swift 69 | print(ODataQueryBuilder().entity("People").search(Search("Name")).build()) 70 | ``` 71 | #### Advanced Query Generation by OData Functions 72 | ```swift 73 | let url = ODataQueryBuilder().entity("People").filter(FilterExp(PropertyFunc("name", .length)).eq().value(30)).build() 74 | print(url) 75 | ``` 76 | ```swift 77 | let url = ODataQueryBuilder().entity("People").filter(FilterExp(PropertyFunc("designation", .substring).value(1)).eq().value("di")).build() 78 | print(url) 79 | ``` 80 | ```swift 81 | let url = ODataQueryBuilder().entity("People").filter(FilterExp(PropertyFunc("CreatedOn", .year)).eq().value(2020)).build() 82 | print(url) 83 | ``` 84 | 85 | #### URL Encode 86 | Use default `.encode()` method to get string presentation of OData URL for network calls 87 | ```swift 88 | let urlEncoded = ODataQueryBuilder().entity("People").search(Search("Name")).encode() 89 | print(urlEncoded) 90 | ``` 91 | 92 | ## Requirements 93 | 94 | **v1.0.0** 95 | It is designed in Swift 5 and supports iOS, macOS, watchOS, tvOS 96 | 97 | ### CocoaPods 98 | 99 | ODataSwift is available through [CocoaPods](http://cocoapods.org). To install 100 | it, simply add the following lines to your Podfile: 101 | 102 | ```ruby 103 | use_frameworks! 104 | pod 'ODataSwift' 105 | ``` 106 | ### Swift Package Manager 107 | 108 | ODataSwift is also available through [Swift Package Manager](https://github.com/apple/swift-package-manager/). 109 | 110 | #### Xcode 111 | 112 | Select `File > Swift Packages > Add Package Dependency...`, 113 | add `https://github.com/developer-celusion/ODataSwift.git` 114 | 115 | [comment]: <> () 116 | 117 | #### CLI 118 | 119 | First, create `Package.swift` that its package declaration includes: 120 | 121 | ```swift 122 | // swift-tools-version:5.0 123 | import PackageDescription 124 | 125 | let package = Package( 126 | name: "MyLibrary", 127 | products: [ 128 | .library(name: "MyLibrary", targets: ["MyLibrary"]), 129 | ], 130 | dependencies: [ 131 | .package(url: "https://github.com/developer-celusion/ODataSwift.git", from: "1.0.0"), 132 | ], 133 | targets: [ 134 | .target(name: "MyLibrary", dependencies: ["ODataSwift"]), 135 | ] 136 | ) 137 | ``` 138 | 139 | Then, type 140 | 141 | ```shell 142 | $ swift build 143 | ``` 144 | 145 | ### To manually add to your project 146 | 147 | 1. Add `Lib/ODataSwift.xcodeproj` to your project 148 | 2. Link `ODataSwift.framework` with your target 149 | 3. Add `Copy Files Build Phase` to include the framework to your application bundle 150 | 151 | _See [iOS Example Project](https://github.com/developer-celusion/ODataSwift/tree/master/Examples/Example-iOS) as reference._ 152 | 153 | [comment]: <> () 154 | 155 | ## Author 156 | 157 | Swapnil Nandgave, developer@celusion.com 158 | 159 | ## License 160 | 161 | ODataSwift is available under the MIT license. See the LICENSE file for more info. 162 | 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /Sources/ODataSwift/Count.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Count.swift 3 | // 4 | // 5 | // Created by Swapnil Nandgave on 02/01/20. 6 | // 7 | 8 | /* 9 | Count is system query option allows clients to request a count of matching resources included with the resources in the response 10 | There are 3 options available 11 | 1. $count in URL - e.g serviceRoot/People/$count 12 | 2. $count in resource response - e.g serviceRoot/People?$count=true 13 | 3. $inlinecount in resource response - serviceRoot/People?$inlinecount= 14 | */ 15 | 16 | import Foundation 17 | 18 | /** 19 | # URLCount 20 | Count is system query option allows clients to request a count of matching resources included with the url 21 | e.g `serviceRoot/People?$count=true` 22 | ~~~ 23 | ODataQueryBuilder().entity("People").onlyCount().build() 24 | ~~~ 25 | - Returns: A URL Count instance which will append in OData URL 26 | */ 27 | 28 | public class URLCount: QueryConvertible { 29 | 30 | private var expression = QueryOption.urlCount.queryText 31 | 32 | public var queryText: String { 33 | return expression 34 | } 35 | 36 | } 37 | 38 | /** 39 | # Count 40 | Count is system query option allows clients to request a count of matching resources included with the resources in the response 41 | e.g `serviceRoot/People?$count=true` 42 | ~~~ 43 | ODataQueryBuilder().entity("People").withCount().build() 44 | ~~~ 45 | - Returns: A Count instance which will include in OData Response 46 | */ 47 | 48 | public class Count: QueryConvertible { 49 | 50 | private var expression = QueryOption.count.queryText 51 | 52 | public var queryText: String { 53 | return expression 54 | } 55 | 56 | } 57 | 58 | /** 59 | # InlineCount 60 | Count is system query option allows clients to request a count of matching resources included with the resources in the response 61 | e.g `serviceRoot/People?$inlinecount=name` 62 | 63 | ~~~ 64 | ODataQueryBuilder().entity("People").inlineCount("Name").build() 65 | ~~~ 66 | 67 | - Parameter property: Property of entity which is to be inlined for count 68 | - Returns: A InlineCount instance which will include in OData Response 69 | */ 70 | 71 | public class InlineCount: QueryConvertible { 72 | 73 | private var expression = QueryOption.inlineCount.queryText 74 | 75 | private var property: String 76 | 77 | /// Property of entity 78 | public init(_ property: Any) { 79 | self.property = String(describing: property) 80 | } 81 | 82 | public var queryText: String { 83 | return self.expression + self.property 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /Sources/ODataSwift/DateTime.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by Swapnil Nandgave on 06/01/20. 6 | // 7 | 8 | import Foundation 9 | 10 | /** 11 | # DateTime 12 | Enum declaration for OData DateTime functions 13 | */ 14 | public enum DateTime:String, QueryConvertible { 15 | /// Compares with current date and time on OData server 16 | case now = "now()" 17 | 18 | /// It returns OData mindatetime functions 19 | case mindatetime = "mindatetime()" 20 | 21 | public var queryText: String { 22 | return self.rawValue 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /Sources/ODataSwift/Error.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Error.swift 3 | // 4 | // 5 | // Created by Swapnil Nandgave on 09/01/20. 6 | // 7 | 8 | import Foundation 9 | 10 | public enum ODataError: Error { 11 | 12 | case urlNotSet 13 | 14 | } 15 | 16 | extension ODataError: LocalizedError { 17 | 18 | public var errorDescription: String? { 19 | switch self { 20 | case .urlNotSet: 21 | return "OData Url is not set. Use ODataQueryBuilder.configure method to set url" 22 | default: 23 | return "" 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /Sources/ODataSwift/Expand.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Expand.swift 3 | // 4 | // 5 | // Created by Swapnil Nandgave on 02/01/20. 6 | // 7 | 8 | import Foundation 9 | 10 | /** 11 | # Expand 12 | The $expand system query option specifies the related resources to be included in line with retrieved resources. 13 | e.g The request below returns people with navigation property Friends of a Person 14 | 15 | ~~~ 16 | serviceRoot/People('keithpinckney')?$expand=Friends 17 | ~~~ 18 | 19 | [See Tutorial](https://www.odata.org/getting-started/basic-tutorial/#expand) 20 | 21 | */ 22 | 23 | public class Expand: QueryConvertible { 24 | 25 | /// Navigational Properties 26 | private var properties = [String]() 27 | 28 | /// Filter block within expand 29 | private var filter: FilterExp? 30 | 31 | /// Select odata properties 32 | private var selects = [String]() 33 | 34 | /// Nested Expand 35 | private var expand: Expand? 36 | 37 | /** 38 | Initializes new Expand with provided navigational property or properties 39 | - Parameter property: Navigational property Name 40 | */ 41 | 42 | public init(_ property: String) { 43 | self.properties = [property] 44 | } 45 | 46 | /** 47 | Initializes new Expand with provided navigational property or properties 48 | - Parameter properties: Navigational property Names 49 | */ 50 | public init(_ properties: [String]) { 51 | self.properties = properties 52 | } 53 | 54 | /** 55 | Append new filter 56 | 57 | ~~~ 58 | $expand=NavProperty($filter=name eq 'martin') 59 | ~~~ 60 | 61 | - Parameter filter: instance of filter class 62 | */ 63 | public func filter(_ filter: FilterExp)-> Self { 64 | self.filter = filter 65 | return self 66 | } 67 | 68 | /** 69 | Append new select 70 | 71 | ~~~ 72 | $expand=NavProperty($select=Name) 73 | ~~~ 74 | 75 | - Parameter select: $select property name of string type 76 | */ 77 | public func select(_ select: String)-> Self { 78 | return self.selects([select]) 79 | } 80 | 81 | /** 82 | Append new select 83 | 84 | ~~~ 85 | $expand=NavProperty($select=Name,Mobile) 86 | ~~~ 87 | 88 | - Parameter selects: $select property name of String data type 89 | */ 90 | public func selects(_ selects: [String])-> Self { 91 | self.selects = selects 92 | return self 93 | } 94 | 95 | /** 96 | Append nested expand 97 | 98 | ~~~ 99 | $expand=NavProperty($expand=NestedExpand) 100 | ~~~ 101 | 102 | - Parameter expand: $expand inside expand 103 | */ 104 | public func expand(_ expand:Expand)-> Self { 105 | self.expand = expand 106 | return self 107 | } 108 | 109 | public var queryText: String { 110 | var temp = ""; 111 | temp += properties.joined(separator: ",") 112 | var part = ""; 113 | if(selects.count > 0) { 114 | part += QueryOption.select.queryText 115 | part += selects.joined(separator: ",") 116 | } 117 | if let filter = self.filter { 118 | requestPart(part: &part) 119 | part += QueryOption.filter.queryText 120 | part += filter.queryText 121 | } 122 | if let expand = self.expand { 123 | requestPart(part: &part) 124 | part += QueryOption.expand.queryText 125 | part += expand.queryText 126 | } 127 | if(part.count > 0) { 128 | temp += "(" + part + ")" 129 | } 130 | return temp 131 | } 132 | 133 | private func requestPart(part: inout String) { 134 | if(part.count > 0) { 135 | part += ";" 136 | } 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /Sources/ODataSwift/Filter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FilterExp.swift 3 | // 4 | // 5 | // Created by Swapnil Nandgave on 02/01/20. 6 | // 7 | 8 | import Foundation 9 | 10 | /// Mode to combine two expressions 11 | public enum BasicOperator: String, QueryConvertible { 12 | 13 | case none = "" 14 | 15 | /** 16 | Add two odata expressions or filter blocks by basic and 17 | 18 | ~~~ 19 | $filter=Name eq 'martin' and usercode eq '0000' 20 | ~~~ 21 | */ 22 | case and = " and " 23 | 24 | /** 25 | Add two odata expressions or filter blocks by basic or 26 | 27 | ~~~ 28 | $filter=Name eq 'martin' or usercode eq '0000' 29 | ~~~ 30 | */ 31 | case or = " or " 32 | 33 | public var queryText: String { 34 | return self.rawValue 35 | } 36 | 37 | } 38 | 39 | /// OData predicate to create expression 40 | public enum Predicate: String, QueryConvertible { 41 | 42 | /** 43 | Create expression with Equal **eq** 44 | 45 | ~~~ 46 | $filter=Name eq 'martin' 47 | ~~~ 48 | */ 49 | case eq = " eq " 50 | 51 | /** 52 | Create expression with Less Than **lt** 53 | 54 | ~~~ 55 | $filter=Age lt 65 56 | ~~~ 57 | */ 58 | case lt = " lt " 59 | 60 | /** 61 | Create expression with Greater than **gt** 62 | 63 | ~~~ 64 | $filter=Age gt 18 65 | ~~~ 66 | */ 67 | case gt = " gt " 68 | 69 | /** 70 | Create expression with Less than equal to **le** 71 | 72 | ~~~ 73 | $filter=Age le 65 74 | ~~~ 75 | */ 76 | case le = " le " 77 | 78 | /** 79 | Create expression with Greater than equal to **ge** 80 | 81 | ~~~ 82 | $filter=Age ge 18 83 | ~~~ 84 | */ 85 | case ge = " ge " 86 | 87 | /** 88 | Create expression with contains operator **contains** 89 | 90 | ~~~ 91 | $filter=contains('name','marti') 92 | ~~~ 93 | */ 94 | case contains = "contains" 95 | 96 | /** 97 | Create expression with endswith operator **endswith** 98 | 99 | ~~~ 100 | $filter=endswith('name','marti') 101 | ~~~ 102 | */ 103 | case endswith = "endswith" 104 | 105 | /** 106 | Create expression with startswith operator **startswith** 107 | 108 | ~~~ 109 | $filter=startswith('name','marti') 110 | ~~~ 111 | */ 112 | case startswith = "startswith" 113 | 114 | public var queryText: String { 115 | return self.rawValue 116 | } 117 | 118 | public var expFirst: Bool { 119 | return (self == .contains || self == .endswith || self == .startswith) 120 | } 121 | 122 | } 123 | 124 | /** 125 | # FilterExp 126 | The $filter system query option allows clients to filter a collection of resources that are addressed by a request URL. The expression specified with $filter is evaluated for each resource in the collection, and only items where the expression evaluates to true are included in the response. 127 | 128 | ~~~ 129 | serviceRoot/People?$filter=FirstName eq 'Scott' 130 | ~~~ 131 | 132 | [See Tutorial](https://www.odata.org/getting-started/basic-tutorial/#filter) 133 | 134 | */ 135 | public class FilterExp: QueryConvertible { 136 | 137 | /// Predicate property name 138 | private var property:String 139 | 140 | /// Predicate 141 | private var filterOption: Predicate? 142 | 143 | /// Value of predicate expression 144 | private var _value:String? 145 | 146 | // MARK: Concating Expression 147 | private var conjection: BasicOperator = .none 148 | 149 | /// Nested Grouped filter which does come under **( )** 150 | private var expression: FilterExp? = nil 151 | 152 | /// Nested Grouped filters which does come under **( )** 153 | private var expressions: [FilterExp] = [FilterExp]() 154 | 155 | /// Initiazes with entity property 156 | public init(_ property:String) { 157 | self.property = property 158 | } 159 | 160 | /// Initializes with property function 161 | public init(_ propertyFunc:PropertyFunc) { 162 | self.property = propertyFunc.queryText 163 | } 164 | 165 | /** 166 | Any value data type. It add ' when type is String otherwise set directly 167 | e.g age eq 10 and name eq 'martin' 168 | */ 169 | public func value(_ value: Any)-> Self { 170 | if value is String { 171 | self._value = "'" + String(describing: value) + "'" 172 | } else { 173 | self._value = String(describing: value) 174 | } 175 | return self 176 | } 177 | 178 | /// Set Date time function as value 179 | public func date(_ dateTime:DateTime)->Self { 180 | self._value = dateTime.queryText 181 | return self 182 | } 183 | 184 | /** 185 | Set formatted date string as value by calling this function. Convert date to string by using DateFormatter and pass as argument 186 | e.g $filter=CreatedOn eq 2020-12-12T10:10:10 187 | */ 188 | public func date(_ value: String)-> Self { 189 | self._value = String(describing: value) 190 | return self 191 | } 192 | 193 | /// Greater than equal to predicate 194 | public func ge()->Self { 195 | self.filterOption = .ge 196 | return self 197 | } 198 | 199 | /// less than equal to predicate 200 | public func le()->Self { 201 | self.filterOption = .le 202 | return self 203 | } 204 | 205 | /// greater than predicate 206 | public func gt()->Self { 207 | self.filterOption = .gt 208 | return self 209 | } 210 | 211 | /// equal to predicate 212 | public func eq()->Self { 213 | self.filterOption = .eq 214 | return self 215 | } 216 | 217 | /// less than predicate 218 | public func lt()->Self { 219 | self.filterOption = .lt 220 | return self 221 | } 222 | 223 | /// contains predicate 224 | public func contains()->Self { 225 | self.filterOption = .contains 226 | return self 227 | } 228 | 229 | /// endswith predicate 230 | public func endswith()->Self { 231 | self.filterOption = .endswith 232 | return self 233 | } 234 | 235 | /// startswith predicate 236 | public func startswith()->Self { 237 | self.filterOption = .startswith 238 | return self 239 | } 240 | 241 | /** 242 | Add filter by Basic Operator **AND** 243 | e.g $filter=Age lt 65 and Name eq 'martin' 244 | */ 245 | public func and(_ expression: FilterExp)->Self { 246 | self.conjection = .and 247 | self.expression = expression 248 | return self 249 | } 250 | 251 | /** 252 | Add filters by Basic Operator **AND**. It will group the array into bracket 253 | e.g $filter=Age lt 65 and (Name eq 'martin') 254 | */ 255 | public func and(_ expressions: [FilterExp])->Self { 256 | self.conjection = .and 257 | self.expressions = expressions 258 | return self 259 | } 260 | 261 | /** 262 | Add filter by Basic Operator **OR** 263 | e.g $filter=Age lt 65 or Name eq 'martin' 264 | */ 265 | public func or(_ expression: FilterExp)->Self { 266 | self.conjection = .or 267 | self.expression = expression 268 | return self 269 | } 270 | 271 | /** 272 | Add filters by Basic Operator **OR**. It will group the array into bracket 273 | e.g $filter=Age lt 65 or (Name eq 'martin') 274 | */ 275 | public func or(_ expressions: [FilterExp])->Self { 276 | self.conjection = .or 277 | self.expressions = expressions 278 | return self 279 | } 280 | 281 | public var queryText: String { 282 | var temp = "" 283 | if let filterOption = filterOption { 284 | if filterOption.expFirst { 285 | temp += filterOption.queryText 286 | temp += "(" + property + "," + (_value ?? "") + ")" 287 | } else { 288 | temp += property 289 | temp += filterOption.queryText 290 | temp += _value ?? "" 291 | } 292 | if let expression = expression { 293 | temp += conjection.queryText + expression.queryText 294 | } 295 | if self.expressions.count > 0 { 296 | temp += conjection.queryText + " (" 297 | for expression in expressions { 298 | temp += expression.queryText 299 | } 300 | temp += ")" 301 | } 302 | } 303 | return temp 304 | } 305 | 306 | } 307 | -------------------------------------------------------------------------------- /Sources/ODataSwift/Funtion.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by Swapnil Nandgave on 06/01/20. 6 | // 7 | 8 | import Foundation 9 | 10 | /// OData Functions 11 | public enum Function: String, QueryConvertible { 12 | 13 | case length = "length" 14 | case tolower = "tolower" 15 | case toupper = "toupper" 16 | case trim = "trim" 17 | case indexof = "indexof" 18 | case substring = "substring" 19 | case year = "year" 20 | case month = "month" 21 | case day = "day" 22 | case hour = "hour" 23 | case minute = "minute" 24 | case second = "second" 25 | case fractionalseconds = "fractionalseconds" 26 | case totaloffsetminutes = "totaloffsetminutes" 27 | 28 | public var hasArgs: Bool { 29 | return (self == .indexof || self == .substring) 30 | } 31 | 32 | public var queryText: String { 33 | return self.rawValue 34 | } 35 | 36 | } 37 | 38 | /// Logicial OData operators used along with $filter. Adding Any / All support to the protocol will greatly improve the expressiveness of OData queries. 39 | public enum LogicalOperator: String, QueryConvertible { 40 | 41 | case any = "any" 42 | case all = "all" 43 | 44 | public var queryText: String { 45 | return "/" + self.rawValue 46 | } 47 | 48 | } 49 | 50 | /** 51 | Adding Any / All support to the protocol will greatly improve the expressiveness of OData queries. 52 | 53 | ~~~ 54 | ~/Movies/?$filter=any(Name eq 'John Belushi') 55 | ~/Orders/?$filter=any(Product/Name eq 'kinect') 56 | ~~~ 57 | 58 | */ 59 | public class OperatorFunc: QueryConvertible { 60 | 61 | /// Property of operator like Name 62 | private var property: String 63 | 64 | /// All or Any 65 | private var propertyOps: LogicalOperator 66 | 67 | /// String presentation of Property Function. Use queryText or String(describing: ) to get the string presentation 68 | private var propertyFunc: String? = nil 69 | 70 | public init(_ property: String,_ propertyOps: LogicalOperator) { 71 | self.property = property 72 | self.propertyOps = propertyOps 73 | } 74 | 75 | public func add(_ propertyFunc: String)-> Self { 76 | self.propertyFunc = propertyFunc 77 | return self 78 | } 79 | 80 | public var queryText: String { 81 | var temp = property + propertyOps.queryText 82 | if let propertyFunc = self.propertyFunc { 83 | temp += "(" + propertyFunc + ")" 84 | } 85 | return temp 86 | } 87 | 88 | } 89 | 90 | /** 91 | It is the part of OperatorFunc to generate inclined property expression. e.g **Name eq 'John Belushi'** 92 | 93 | ~~~ 94 | ~/Movies/?$filter=any(Name eq 'John Belushi') 95 | ~/Orders/?$filter=any(Product/Name eq 'kinect') 96 | ~~~ 97 | 98 | */ 99 | public class PropertyFunc: QueryConvertible, CustomStringConvertible { 100 | 101 | private var name: String 102 | private var function: Function 103 | private var _value: String? = nil 104 | 105 | public init(_ name:String,_ function: Function) { 106 | self.name = name 107 | self.function = function 108 | } 109 | 110 | public func value(_ value: Any)->Self { 111 | if value is String { 112 | self._value = "'" + String(describing: value) + "'" 113 | } else { 114 | self._value = String(describing: value) 115 | } 116 | return self 117 | } 118 | 119 | public var queryText: String { 120 | var temp = function.queryText 121 | temp += "(" + name 122 | if let value = self._value, function.hasArgs { 123 | temp += ", " + value 124 | } 125 | temp += ")" 126 | return temp 127 | } 128 | 129 | public var description: String { 130 | return queryText 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /Sources/ODataSwift/ODataQueryBuilder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ODataQueryBuilder.swift 3 | // ODataQueryBuilder 4 | // 5 | // Created by Celusion Technologies on 16/03/18. 6 | // 7 | 8 | import Foundation 9 | 10 | /** 11 | # ODataQueryBuilder 12 | 13 | OData (Open Data Protocol) is an ISO/IEC approved, OASIS standard that defines a set of best practices for building and consuming RESTful APIs. OData helps you focus on your business logic while building RESTful APIs without having to worry about the various approaches to define request and response headers, status codes, HTTP methods, URL conventions, media types, payload formats, query options, etc. OData also provides guidance for tracking changes, defining functions/actions for reusable procedures, and sending asynchronous/batch requests. 14 | 15 | OData RESTful APIs are easy to consume. The OData metadata, a machine-readable description of the data model of the APIs, enables the creation of powerful generic client proxies and tools. 16 | 17 | ODataQueryBuilder is utility class to generate OData Queries and providing almost all the operators and functions like $filter, $expand, $select, $search etc. You can build the oData query and execute 18 | on OData server to get required resource results 19 | 20 | [Basic Tutorial](https://www.odata.org/getting-started/basic-tutorial/) 21 | 22 | */ 23 | 24 | public class ODataQueryBuilder: QueryConvertible { 25 | 26 | public typealias ODQueBuilder = ODataQueryBuilder 27 | 28 | private static var url: String? = nil 29 | 30 | private static let INVALID = -990 31 | private var entityName: String? = nil 32 | private var selects = [String]() 33 | private var filters = [FilterExp]() 34 | private var expands = [Expand]() 35 | private var orders = [Order]() 36 | private var search: Search? = nil 37 | private var urlCount: URLCount? = nil 38 | private var count: Count? = nil 39 | private var inlineCount: InlineCount? = nil 40 | private var skip : Int = INVALID 41 | private var top : Int = INVALID 42 | private var id = "" 43 | private var unboundFunc = "" 44 | private var boundFunc = "" 45 | 46 | private var skipMultiplier = -1; 47 | private var interval = ODataQueryBuilder.INVALID 48 | 49 | public static func configure(url: String) { 50 | ODataQueryBuilder.url = url 51 | } 52 | 53 | public init() { 54 | if Self.url == nil { 55 | fatalError(ODataError.urlNotSet.localizedDescription) 56 | } 57 | self.entityName = nil 58 | self.selects = [String]() 59 | self.filters = [FilterExp]() 60 | self.expands = [Expand]() 61 | self.orders = [Order]() 62 | self.urlCount = nil 63 | self.skip = Self.INVALID 64 | self.top = Self.INVALID 65 | self.id = "" 66 | } 67 | 68 | /// Append Entity e.g serviceRoot/People 69 | public func entity(_ value: String) -> Self { 70 | self.entityName = value 71 | return self 72 | } 73 | 74 | /** 75 | Append Select query option 76 | 77 | ~~~ 78 | serviceRoot/People?$select=Name 79 | ~~~ 80 | 81 | */ 82 | public func select(_ value: String)-> Self { 83 | self.selects([value]) 84 | } 85 | 86 | /** 87 | Append Select query option 88 | 89 | ~~~ 90 | serviceRoot/People?$select=ID, Name 91 | ~~~ 92 | 93 | */ 94 | public func selects(_ values:[String]) -> Self { 95 | if(values.count > 0) { 96 | self.selects = values 97 | } 98 | return self 99 | } 100 | 101 | /** 102 | Append Filter query option 103 | 104 | ~~~ 105 | serviceRoot/People?$filter=Name eq 'Martin' 106 | ~~~ 107 | 108 | */ 109 | 110 | public func filter(_ value: FilterExp)-> Self { 111 | self.filters = [value] 112 | return self 113 | } 114 | 115 | /** 116 | Append Filter query option 117 | 118 | ~~~ 119 | serviceRoot/People?$search=Boise 120 | ~~~ 121 | 122 | */ 123 | 124 | public func search(_ value: Search)-> Self { 125 | self.search = value 126 | return self 127 | } 128 | 129 | /** 130 | Append Expand query option 131 | 132 | ~~~ 133 | serviceRoot/People?$expand=Address 134 | ~~~ 135 | 136 | */ 137 | 138 | public func expand(_ value: Expand)-> Self { 139 | self.expands.append(value) 140 | return self 141 | } 142 | 143 | /** 144 | Append Expand query option 145 | 146 | ~~~ 147 | serviceRoot/People?$expand=Address, ContactDetail 148 | ~~~ 149 | 150 | */ 151 | 152 | public func expands(_ values: [Expand])-> Self { 153 | if(values.count > 0) { 154 | self.expands.append(contentsOf: values); 155 | } 156 | return self 157 | } 158 | 159 | /** 160 | Append Order query option 161 | 162 | ~~~ 163 | serviceRoot/People?$orderby=ID desc 164 | ~~~ 165 | 166 | */ 167 | 168 | public func order(_ value: Order)-> Self { 169 | return self.orders([value]) 170 | } 171 | 172 | /** 173 | Append Order query option 174 | 175 | ~~~ 176 | serviceRoot/People?$orderby=ID desc, name asc 177 | ~~~ 178 | 179 | */ 180 | 181 | public func orders(_ values: [Order])-> Self { 182 | if(values.count > 0) { 183 | self.orders = values 184 | } 185 | return self 186 | } 187 | 188 | /** 189 | Append Skip query option 190 | 191 | ~~~ 192 | serviceRoot/People?$skip=10 193 | ~~~ 194 | 195 | */ 196 | 197 | public func skip(_ value: Int)-> Self { 198 | self.skip = value 199 | return self 200 | } 201 | 202 | /** 203 | Append Skip query option 204 | 205 | ~~~ 206 | serviceRoot/People?$top=10 207 | ~~~ 208 | 209 | */ 210 | 211 | public func top(_ value: Int)-> Self { 212 | self.top = value 213 | return self 214 | } 215 | 216 | /** 217 | Append ID query option. ID is Primary key of Entity 218 | 219 | ~~~ 220 | serviceRoot/People('Martin') 221 | serviceRoot/Address(10) 222 | ~~~ 223 | 224 | */ 225 | 226 | public func id(_ id:Any,_ segmentProperty: String? = nil)-> Self { 227 | if let str = id as? String { 228 | self.id = "('"+String(describing:str)+"')"; 229 | } else { 230 | self.id = "("+String(describing: id)+")" 231 | } 232 | if let segmentProperty = segmentProperty { 233 | if !segmentProperty.hasPrefix("/") { 234 | self.id += "/" 235 | } 236 | self.id += segmentProperty 237 | } 238 | return self 239 | } 240 | 241 | /** 242 | Append bound OData function e.g Need to pass **Microsoft.OData.SampleService.Models.TripPin.GetFavoriteAirline()** along with / 243 | 244 | ~~~ 245 | serviceRoot/People('russellwhyte')/Microsoft.OData.SampleService.Models.TripPin.GetFavoriteAirline() 246 | ~~~ 247 | 248 | */ 249 | public func boundFunction(_ name: String)->Self { 250 | self.boundFunc = name 251 | return self 252 | } 253 | 254 | /** 255 | Append unbound OData function. e.g Need to pass **GetNearestAirport(lat = 33, lon = -118)** along with / 256 | 257 | ~~~ 258 | serviceRoot/GetNearestAirport(lat = 33, lon = -118) 259 | ~~~ 260 | 261 | */ 262 | public func unboundFunction(_ name: String)->Self { 263 | self.unboundFunc = name 264 | return self 265 | } 266 | 267 | /// Appends /$count in OData Query URL 268 | public func onlyCount()-> Self { 269 | self.urlCount = URLCount() 270 | return self 271 | } 272 | 273 | /// Appends $count=true as params 274 | public func withCount()-> Self { 275 | self.count = Count() 276 | return self 277 | } 278 | 279 | /// Appends $inlinecount=name as params 280 | public func inlineCount(_ property: String)-> Self { 281 | self.inlineCount = InlineCount(property) 282 | return self 283 | } 284 | 285 | /// Forms url and return in plain String. .encode will return encoded url which you can use in network calls 286 | public func build()-> String { 287 | var temp = queryUrlPart() 288 | if self.unboundFunc.count > 0 { 289 | temp += self.unboundFunc 290 | } 291 | temp += idPart() 292 | if self.boundFunc.count > 0 { 293 | temp += self.boundFunc 294 | } 295 | if urlCount != nil { 296 | temp += urlCount!.queryText 297 | } 298 | if(isExp()) { 299 | temp += expPart() 300 | temp += userQueryPart() 301 | } 302 | return temp 303 | } 304 | 305 | /// Returns url in plain text 306 | public var queryText: String { 307 | return build() 308 | } 309 | 310 | /// Returns encoded url which can be used in Network calls 311 | public func encode()->String { 312 | var temp = build() 313 | temp = temp.replacingOccurrences(of: " ", with: "%20").replacingOccurrences(of: "+", with: "%2B") 314 | return temp 315 | } 316 | 317 | /// Use this method to initialize pagination 318 | public func paginate(interval: Int)->Self { 319 | skipMultiplier = -1; 320 | self.interval = interval 321 | return self 322 | } 323 | 324 | /// Use this method to get next page and call build or encode to get next page OData URL 325 | public func nextPage() { 326 | if(interval != Self.INVALID) { 327 | skipMultiplier += 1 328 | self.top = self.interval 329 | self.skip = skipMultiplier * self.interval 330 | } else { 331 | print("Interval is missing") 332 | } 333 | } 334 | 335 | private func queryUrlPart()-> String { 336 | if let base = Self.url, let entity = entityName { 337 | var temp = base 338 | temp += temp.hasSuffix("/") ? "" : "/" 339 | temp += entity 340 | return temp 341 | } else { 342 | return "" 343 | } 344 | } 345 | 346 | private func idPart()-> String { 347 | return id 348 | } 349 | 350 | private func expPart() -> String { 351 | if(isExp()) { 352 | return "?" 353 | } else { 354 | return "" 355 | } 356 | } 357 | 358 | private func userQueryPart() -> String { 359 | var temp = ""; 360 | if let count = self.count { 361 | temp += count.queryText 362 | } 363 | if let inlineCount = inlineCount { 364 | temp += inlineCount.queryText 365 | } 366 | if let search = self.search { 367 | temp += search.queryText 368 | } 369 | if(selects.count > 0) { 370 | temp += QueryOption.select.rawValue 371 | temp += selects.joined(separator: ",") 372 | } 373 | if(filters.count > 0) { 374 | requestPart(part: &temp) 375 | temp += QueryOption.filter.rawValue 376 | filters.forEach { item in 377 | temp += item.queryText 378 | } 379 | } 380 | if(expands.count > 0) { 381 | requestPart(part: &temp) 382 | temp += QueryOption.expand.rawValue 383 | var list = [String]() 384 | expands.forEach { order in 385 | list.append(order.queryText) 386 | } 387 | temp += list.joined(separator: ",") 388 | } 389 | if(orders.count > 0) { 390 | requestPart(part: &temp) 391 | temp += QueryOption.order.rawValue 392 | var list = [String]() 393 | orders.forEach { order in 394 | list.append(order.queryText) 395 | } 396 | temp += list.joined(separator: ",") 397 | } 398 | if(skip != Self.INVALID) { 399 | requestPart(part: &temp) 400 | temp += QueryOption.skip.rawValue 401 | temp += String(skip) 402 | } 403 | if(top != Self.INVALID) { 404 | requestPart(part: &temp) 405 | temp += QueryOption.top.rawValue 406 | temp += String(top) 407 | } 408 | return temp 409 | } 410 | 411 | private func requestPart(part : inout String) { 412 | if(part.count > 0) { 413 | part += "&" 414 | } 415 | } 416 | 417 | private func isExp() -> Bool { 418 | if(selects.count > 0 || filters.count > 0 || search != nil || expands.count > 0 || orders.count > 0 || skip != Self.INVALID || top != Self.INVALID || count != nil || inlineCount != nil) { 419 | return true 420 | } else { 421 | return false 422 | } 423 | } 424 | 425 | } 426 | -------------------------------------------------------------------------------- /Sources/ODataSwift/Order.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Order.swift 3 | // 4 | // 5 | // Created by Swapnil Nandgave on 02/01/20. 6 | // 7 | 8 | import Foundation 9 | 10 | public enum OrderType: String, QueryConvertible { 11 | 12 | /// ascending order 13 | case asc = "asc" 14 | 15 | /// descending order 16 | case desc = "desc" 17 | 18 | public var queryText: String { 19 | return self.rawValue 20 | } 21 | 22 | } 23 | 24 | /** 25 | The $orderby system query option allows clients to request resources in either ascending order using asc or descending order using desc. If asc or desc not specified, then the resources will be ordered in ascending order. The request below orders Trips on property EndsAt in descending order. 26 | 27 | ~~~ 28 | serviceRoot/People('scottketchum')/Trips?$orderby=EndsAt desc 29 | ~~~ 30 | */ 31 | 32 | public class Order: QueryConvertible { 33 | 34 | private var property: String 35 | private var orderType = OrderType.asc 36 | 37 | public convenience init(_ property:String) { 38 | self.init(property,orderType: .asc) 39 | } 40 | 41 | public init(_ property:String, orderType:OrderType) { 42 | self.property = property 43 | self.orderType = orderType 44 | } 45 | 46 | public var queryText: String { 47 | var temp = property 48 | temp += " " 49 | temp += String(describing: orderType) 50 | return temp 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /Sources/ODataSwift/QueryConvertible.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QueryConvertible.swift 3 | // 4 | // 5 | // Created by Swapnil Nandgave on 02/01/20. 6 | // 7 | 8 | import Foundation 9 | 10 | /// OData Query Representation 11 | public protocol QueryConvertible { 12 | 13 | var queryText: String { get } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /Sources/ODataSwift/QueryOption.swift: -------------------------------------------------------------------------------- 1 | // 2 | // QueryOption.swift 3 | // 4 | // 5 | // Created by Swapnil Nandgave on 02/01/20. 6 | // 7 | 8 | import Foundation 9 | 10 | /** 11 | OData supports various kinds of query options for querying data. This section will help you go through the common scenarios for these query options. 12 | */ 13 | 14 | public enum QueryOption: String, QueryConvertible { 15 | 16 | case select = "$select=" 17 | case filter = "$filter=" 18 | case expand = "$expand=" 19 | case order = "$orderby=" 20 | case skip = "$skip=" 21 | case top = "$top=" 22 | case urlCount = "/$count" 23 | case count = "$count=true" 24 | case inlineCount = "$inlinecount=" 25 | case search = "$search=" 26 | 27 | public var queryText: String { 28 | return self.rawValue 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /Sources/ODataSwift/Search.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by Swapnil Nandgave on 06/01/20. 6 | // 7 | 8 | import Foundation 9 | 10 | /** 11 | The $search system query option restricts the result to include only those entities matching the specified search expression. The definition of what it means to match is dependent upon the implementation. The request below get all People who has 'Boise' in their contents. 12 | 13 | ~~~ 14 | serviceRoot/People?$search=Boise 15 | ~~~ 16 | 17 | */ 18 | 19 | public class Search: QueryConvertible { 20 | 21 | private var expression = QueryOption.search.queryText 22 | 23 | private var property: String 24 | 25 | public init(_ property: String) { 26 | self.property = property 27 | } 28 | 29 | public var queryText: String { 30 | return self.expression + self.property 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | import ODataSwiftTests 4 | 5 | var tests = [XCTestCaseEntry]() 6 | tests += ODataSwiftTests.allTests() 7 | XCTMain(tests) 8 | -------------------------------------------------------------------------------- /Tests/ODataSwiftTests/ODataSwiftTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import ODataSwift 3 | 4 | final class ODataSwiftTests: XCTestCase { 5 | func testExample() { 6 | // This is an example of a functional test case. 7 | // Use XCTAssert and related functions to verify your tests produce the correct 8 | // results. 9 | XCTAssertEqual("Hello, World!", "Hello, World!") 10 | } 11 | 12 | static var allTests = [ 13 | ("testExample", testExample), 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /Tests/ODataSwiftTests/XCTestManifests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | #if !canImport(ObjectiveC) 4 | public func allTests() -> [XCTestCaseEntry] { 5 | return [ 6 | testCase(ODataSwiftTests.allTests), 7 | ] 8 | } 9 | #endif 10 | --------------------------------------------------------------------------------