├── .gitignore ├── .gitmodules ├── .travis.yml ├── README.md ├── swift-couchdb.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ ├── swift-couchdb.xccheckout │ │ └── swift-couchdb.xcscmblueprint │ └── xcuserdata │ │ └── zemirco.xcuserdatad │ │ └── UserInterfaceState.xcuserstate ├── xcshareddata │ └── xcschemes │ │ └── swift-couchdb.xcscheme └── xcuserdata │ └── zemirco.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── swift-couchdb ├── AppDelegate.swift ├── Base.lproj │ ├── LaunchScreen.xib │ └── Main.storyboard ├── CouchDB.swift ├── Images.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Info.plist ├── MyDocument.swift ├── QueryString.swift └── ViewController.swift └── swift-couchdbTests ├── Info.plist └── swift_couchdbTests.swift /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Alamofire"] 2 | path = Alamofire 3 | url = https://github.com/Alamofire/Alamofire.git 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | 2 | services: 3 | - couchdb 4 | 5 | language: objective-c 6 | 7 | osx_image: xcode7.1 8 | 9 | xcode_project: swift-couchdb.xcodeproj 10 | 11 | xcode_scheme: swift-couchdb 12 | 13 | xcode_sdk: iphonesimulator 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # swift-couchdb 3 | 4 | [![Build Status](https://travis-ci.org/zemirco/swift-couchdb.svg)](https://travis-ci.org/zemirco/swift-couchdb) 5 | 6 | CouchDB client for Swift. 7 | 8 | ## Installation 9 | 10 | 1. Install [swift-http](https://github.com/zemirco/swift-http) 11 | 2. Copy `CouchDB.swift` from `./swift-couchdb/` into your project. 12 | 13 | ## Usage 14 | 15 | ```swift 16 | 17 | // create new client 18 | var couchdb = CouchDB(url: "http://localhost:5984", name: nil, password: nil) 19 | 20 | // use database 21 | var database = couchdb.use("mydb") 22 | 23 | // get document by id 24 | database.get("abc123") { response in 25 | switch response { 26 | case .Error(let error): 27 | println(error) 28 | case .Success(let data): 29 | println(data) 30 | } 31 | } 32 | ``` 33 | 34 | ## Test 35 | 36 | cmd + u 37 | 38 | ## License 39 | 40 | MIT 41 | -------------------------------------------------------------------------------- /swift-couchdb.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 3B046B181B9573480090B77C /* MyDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B046B171B9573480090B77C /* MyDocument.swift */; }; 11 | 3B068AFB1B34A21E00F27CBF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B068AFA1B34A21E00F27CBF /* AppDelegate.swift */; }; 12 | 3B068AFD1B34A21E00F27CBF /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B068AFC1B34A21E00F27CBF /* ViewController.swift */; }; 13 | 3B068B001B34A21E00F27CBF /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3B068AFE1B34A21E00F27CBF /* Main.storyboard */; }; 14 | 3B068B021B34A21E00F27CBF /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3B068B011B34A21E00F27CBF /* Images.xcassets */; }; 15 | 3B068B051B34A21E00F27CBF /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 3B068B031B34A21E00F27CBF /* LaunchScreen.xib */; }; 16 | 3B068B111B34A21E00F27CBF /* swift_couchdbTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B068B101B34A21E00F27CBF /* swift_couchdbTests.swift */; }; 17 | 3B4BF0091DB1F60500F3CBD0 /* QueryString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B4BF0081DB1F60500F3CBD0 /* QueryString.swift */; }; 18 | 3BE25E321B9C8A70008705F6 /* CouchDB.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BE25E311B9C8A70008705F6 /* CouchDB.swift */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXContainerItemProxy section */ 22 | 3B068B0B1B34A21E00F27CBF /* PBXContainerItemProxy */ = { 23 | isa = PBXContainerItemProxy; 24 | containerPortal = 3B068AED1B34A21E00F27CBF /* Project object */; 25 | proxyType = 1; 26 | remoteGlobalIDString = 3B068AF41B34A21E00F27CBF; 27 | remoteInfo = "swift-couchdb"; 28 | }; 29 | 3B1B09261E47B3380060A062 /* PBXContainerItemProxy */ = { 30 | isa = PBXContainerItemProxy; 31 | containerPortal = 3B1B091B1E47B3380060A062 /* Alamofire.xcodeproj */; 32 | proxyType = 2; 33 | remoteGlobalIDString = F8111E3319A95C8B0040E7D1; 34 | remoteInfo = "Alamofire iOS"; 35 | }; 36 | 3B1B09281E47B3380060A062 /* PBXContainerItemProxy */ = { 37 | isa = PBXContainerItemProxy; 38 | containerPortal = 3B1B091B1E47B3380060A062 /* Alamofire.xcodeproj */; 39 | proxyType = 2; 40 | remoteGlobalIDString = F8111E3E19A95C8B0040E7D1; 41 | remoteInfo = "Alamofire iOS Tests"; 42 | }; 43 | 3B1B092A1E47B3380060A062 /* PBXContainerItemProxy */ = { 44 | isa = PBXContainerItemProxy; 45 | containerPortal = 3B1B091B1E47B3380060A062 /* Alamofire.xcodeproj */; 46 | proxyType = 2; 47 | remoteGlobalIDString = 4DD67C0B1A5C55C900ED2280; 48 | remoteInfo = "Alamofire macOS"; 49 | }; 50 | 3B1B092C1E47B3380060A062 /* PBXContainerItemProxy */ = { 51 | isa = PBXContainerItemProxy; 52 | containerPortal = 3B1B091B1E47B3380060A062 /* Alamofire.xcodeproj */; 53 | proxyType = 2; 54 | remoteGlobalIDString = F829C6B21A7A94F100A2CD59; 55 | remoteInfo = "Alamofire macOS Tests"; 56 | }; 57 | 3B1B092E1E47B3380060A062 /* PBXContainerItemProxy */ = { 58 | isa = PBXContainerItemProxy; 59 | containerPortal = 3B1B091B1E47B3380060A062 /* Alamofire.xcodeproj */; 60 | proxyType = 2; 61 | remoteGlobalIDString = 4CF626EF1BA7CB3E0011A099; 62 | remoteInfo = "Alamofire tvOS"; 63 | }; 64 | 3B1B09301E47B3380060A062 /* PBXContainerItemProxy */ = { 65 | isa = PBXContainerItemProxy; 66 | containerPortal = 3B1B091B1E47B3380060A062 /* Alamofire.xcodeproj */; 67 | proxyType = 2; 68 | remoteGlobalIDString = 4CF626F81BA7CB3E0011A099; 69 | remoteInfo = "Alamofire tvOS Tests"; 70 | }; 71 | 3B1B09321E47B3380060A062 /* PBXContainerItemProxy */ = { 72 | isa = PBXContainerItemProxy; 73 | containerPortal = 3B1B091B1E47B3380060A062 /* Alamofire.xcodeproj */; 74 | proxyType = 2; 75 | remoteGlobalIDString = E4202FE01B667AA100C997FB; 76 | remoteInfo = "Alamofire watchOS"; 77 | }; 78 | /* End PBXContainerItemProxy section */ 79 | 80 | /* Begin PBXFileReference section */ 81 | 3B046B171B9573480090B77C /* MyDocument.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyDocument.swift; sourceTree = ""; }; 82 | 3B068AF51B34A21E00F27CBF /* swift-couchdb.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "swift-couchdb.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 83 | 3B068AF91B34A21E00F27CBF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 84 | 3B068AFA1B34A21E00F27CBF /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 85 | 3B068AFC1B34A21E00F27CBF /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 86 | 3B068AFF1B34A21E00F27CBF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 87 | 3B068B011B34A21E00F27CBF /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 88 | 3B068B041B34A21E00F27CBF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 89 | 3B068B0A1B34A21E00F27CBF /* swift-couchdbTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "swift-couchdbTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 90 | 3B068B0F1B34A21E00F27CBF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 91 | 3B068B101B34A21E00F27CBF /* swift_couchdbTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = swift_couchdbTests.swift; sourceTree = ""; }; 92 | 3B1B091B1E47B3380060A062 /* Alamofire.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Alamofire.xcodeproj; path = Alamofire/Alamofire.xcodeproj; sourceTree = ""; }; 93 | 3B4BF0081DB1F60500F3CBD0 /* QueryString.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryString.swift; sourceTree = ""; }; 94 | 3BE25E311B9C8A70008705F6 /* CouchDB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CouchDB.swift; sourceTree = ""; }; 95 | /* End PBXFileReference section */ 96 | 97 | /* Begin PBXFrameworksBuildPhase section */ 98 | 3B068AF21B34A21E00F27CBF /* Frameworks */ = { 99 | isa = PBXFrameworksBuildPhase; 100 | buildActionMask = 2147483647; 101 | files = ( 102 | ); 103 | runOnlyForDeploymentPostprocessing = 0; 104 | }; 105 | 3B068B071B34A21E00F27CBF /* Frameworks */ = { 106 | isa = PBXFrameworksBuildPhase; 107 | buildActionMask = 2147483647; 108 | files = ( 109 | ); 110 | runOnlyForDeploymentPostprocessing = 0; 111 | }; 112 | /* End PBXFrameworksBuildPhase section */ 113 | 114 | /* Begin PBXGroup section */ 115 | 3B068AEC1B34A21E00F27CBF = { 116 | isa = PBXGroup; 117 | children = ( 118 | 3B1B091B1E47B3380060A062 /* Alamofire.xcodeproj */, 119 | 3B068AF71B34A21E00F27CBF /* swift-couchdb */, 120 | 3B068B0D1B34A21E00F27CBF /* swift-couchdbTests */, 121 | 3B068AF61B34A21E00F27CBF /* Products */, 122 | ); 123 | sourceTree = ""; 124 | }; 125 | 3B068AF61B34A21E00F27CBF /* Products */ = { 126 | isa = PBXGroup; 127 | children = ( 128 | 3B068AF51B34A21E00F27CBF /* swift-couchdb.app */, 129 | 3B068B0A1B34A21E00F27CBF /* swift-couchdbTests.xctest */, 130 | ); 131 | name = Products; 132 | sourceTree = ""; 133 | }; 134 | 3B068AF71B34A21E00F27CBF /* swift-couchdb */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | 3B068AFA1B34A21E00F27CBF /* AppDelegate.swift */, 138 | 3B068AFC1B34A21E00F27CBF /* ViewController.swift */, 139 | 3B046B171B9573480090B77C /* MyDocument.swift */, 140 | 3BE25E311B9C8A70008705F6 /* CouchDB.swift */, 141 | 3B4BF0081DB1F60500F3CBD0 /* QueryString.swift */, 142 | 3B068AFE1B34A21E00F27CBF /* Main.storyboard */, 143 | 3B068B011B34A21E00F27CBF /* Images.xcassets */, 144 | 3B068B031B34A21E00F27CBF /* LaunchScreen.xib */, 145 | 3B068AF81B34A21E00F27CBF /* Supporting Files */, 146 | ); 147 | path = "swift-couchdb"; 148 | sourceTree = ""; 149 | }; 150 | 3B068AF81B34A21E00F27CBF /* Supporting Files */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | 3B068AF91B34A21E00F27CBF /* Info.plist */, 154 | ); 155 | name = "Supporting Files"; 156 | sourceTree = ""; 157 | }; 158 | 3B068B0D1B34A21E00F27CBF /* swift-couchdbTests */ = { 159 | isa = PBXGroup; 160 | children = ( 161 | 3B068B101B34A21E00F27CBF /* swift_couchdbTests.swift */, 162 | 3B068B0E1B34A21E00F27CBF /* Supporting Files */, 163 | ); 164 | path = "swift-couchdbTests"; 165 | sourceTree = ""; 166 | }; 167 | 3B068B0E1B34A21E00F27CBF /* Supporting Files */ = { 168 | isa = PBXGroup; 169 | children = ( 170 | 3B068B0F1B34A21E00F27CBF /* Info.plist */, 171 | ); 172 | name = "Supporting Files"; 173 | sourceTree = ""; 174 | }; 175 | 3B1B091C1E47B3380060A062 /* Products */ = { 176 | isa = PBXGroup; 177 | children = ( 178 | 3B1B09271E47B3380060A062 /* Alamofire.framework */, 179 | 3B1B09291E47B3380060A062 /* Alamofire iOS Tests.xctest */, 180 | 3B1B092B1E47B3380060A062 /* Alamofire.framework */, 181 | 3B1B092D1E47B3380060A062 /* Alamofire macOS Tests.xctest */, 182 | 3B1B092F1E47B3380060A062 /* Alamofire.framework */, 183 | 3B1B09311E47B3380060A062 /* Alamofire tvOS Tests.xctest */, 184 | 3B1B09331E47B3380060A062 /* Alamofire.framework */, 185 | ); 186 | name = Products; 187 | sourceTree = ""; 188 | }; 189 | /* End PBXGroup section */ 190 | 191 | /* Begin PBXNativeTarget section */ 192 | 3B068AF41B34A21E00F27CBF /* swift-couchdb */ = { 193 | isa = PBXNativeTarget; 194 | buildConfigurationList = 3B068B141B34A21E00F27CBF /* Build configuration list for PBXNativeTarget "swift-couchdb" */; 195 | buildPhases = ( 196 | 3B068AF11B34A21E00F27CBF /* Sources */, 197 | 3B068AF21B34A21E00F27CBF /* Frameworks */, 198 | 3B068AF31B34A21E00F27CBF /* Resources */, 199 | ); 200 | buildRules = ( 201 | ); 202 | dependencies = ( 203 | ); 204 | name = "swift-couchdb"; 205 | productName = "swift-couchdb"; 206 | productReference = 3B068AF51B34A21E00F27CBF /* swift-couchdb.app */; 207 | productType = "com.apple.product-type.application"; 208 | }; 209 | 3B068B091B34A21E00F27CBF /* swift-couchdbTests */ = { 210 | isa = PBXNativeTarget; 211 | buildConfigurationList = 3B068B171B34A21E00F27CBF /* Build configuration list for PBXNativeTarget "swift-couchdbTests" */; 212 | buildPhases = ( 213 | 3B068B061B34A21E00F27CBF /* Sources */, 214 | 3B068B071B34A21E00F27CBF /* Frameworks */, 215 | 3B068B081B34A21E00F27CBF /* Resources */, 216 | ); 217 | buildRules = ( 218 | ); 219 | dependencies = ( 220 | 3B068B0C1B34A21E00F27CBF /* PBXTargetDependency */, 221 | ); 222 | name = "swift-couchdbTests"; 223 | productName = "swift-couchdbTests"; 224 | productReference = 3B068B0A1B34A21E00F27CBF /* swift-couchdbTests.xctest */; 225 | productType = "com.apple.product-type.bundle.unit-test"; 226 | }; 227 | /* End PBXNativeTarget section */ 228 | 229 | /* Begin PBXProject section */ 230 | 3B068AED1B34A21E00F27CBF /* Project object */ = { 231 | isa = PBXProject; 232 | attributes = { 233 | LastSwiftMigration = 0700; 234 | LastSwiftUpdateCheck = 0700; 235 | LastUpgradeCheck = 0820; 236 | ORGANIZATIONNAME = zemirco; 237 | TargetAttributes = { 238 | 3B068AF41B34A21E00F27CBF = { 239 | CreatedOnToolsVersion = 6.3.2; 240 | LastSwiftMigration = 0800; 241 | }; 242 | 3B068B091B34A21E00F27CBF = { 243 | CreatedOnToolsVersion = 6.3.2; 244 | LastSwiftMigration = 0800; 245 | TestTargetID = 3B068AF41B34A21E00F27CBF; 246 | }; 247 | }; 248 | }; 249 | buildConfigurationList = 3B068AF01B34A21E00F27CBF /* Build configuration list for PBXProject "swift-couchdb" */; 250 | compatibilityVersion = "Xcode 3.2"; 251 | developmentRegion = English; 252 | hasScannedForEncodings = 0; 253 | knownRegions = ( 254 | en, 255 | Base, 256 | ); 257 | mainGroup = 3B068AEC1B34A21E00F27CBF; 258 | productRefGroup = 3B068AF61B34A21E00F27CBF /* Products */; 259 | projectDirPath = ""; 260 | projectReferences = ( 261 | { 262 | ProductGroup = 3B1B091C1E47B3380060A062 /* Products */; 263 | ProjectRef = 3B1B091B1E47B3380060A062 /* Alamofire.xcodeproj */; 264 | }, 265 | ); 266 | projectRoot = ""; 267 | targets = ( 268 | 3B068AF41B34A21E00F27CBF /* swift-couchdb */, 269 | 3B068B091B34A21E00F27CBF /* swift-couchdbTests */, 270 | ); 271 | }; 272 | /* End PBXProject section */ 273 | 274 | /* Begin PBXReferenceProxy section */ 275 | 3B1B09271E47B3380060A062 /* Alamofire.framework */ = { 276 | isa = PBXReferenceProxy; 277 | fileType = wrapper.framework; 278 | path = Alamofire.framework; 279 | remoteRef = 3B1B09261E47B3380060A062 /* PBXContainerItemProxy */; 280 | sourceTree = BUILT_PRODUCTS_DIR; 281 | }; 282 | 3B1B09291E47B3380060A062 /* Alamofire iOS Tests.xctest */ = { 283 | isa = PBXReferenceProxy; 284 | fileType = wrapper.cfbundle; 285 | path = "Alamofire iOS Tests.xctest"; 286 | remoteRef = 3B1B09281E47B3380060A062 /* PBXContainerItemProxy */; 287 | sourceTree = BUILT_PRODUCTS_DIR; 288 | }; 289 | 3B1B092B1E47B3380060A062 /* Alamofire.framework */ = { 290 | isa = PBXReferenceProxy; 291 | fileType = wrapper.framework; 292 | path = Alamofire.framework; 293 | remoteRef = 3B1B092A1E47B3380060A062 /* PBXContainerItemProxy */; 294 | sourceTree = BUILT_PRODUCTS_DIR; 295 | }; 296 | 3B1B092D1E47B3380060A062 /* Alamofire macOS Tests.xctest */ = { 297 | isa = PBXReferenceProxy; 298 | fileType = wrapper.cfbundle; 299 | path = "Alamofire macOS Tests.xctest"; 300 | remoteRef = 3B1B092C1E47B3380060A062 /* PBXContainerItemProxy */; 301 | sourceTree = BUILT_PRODUCTS_DIR; 302 | }; 303 | 3B1B092F1E47B3380060A062 /* Alamofire.framework */ = { 304 | isa = PBXReferenceProxy; 305 | fileType = wrapper.framework; 306 | path = Alamofire.framework; 307 | remoteRef = 3B1B092E1E47B3380060A062 /* PBXContainerItemProxy */; 308 | sourceTree = BUILT_PRODUCTS_DIR; 309 | }; 310 | 3B1B09311E47B3380060A062 /* Alamofire tvOS Tests.xctest */ = { 311 | isa = PBXReferenceProxy; 312 | fileType = wrapper.cfbundle; 313 | path = "Alamofire tvOS Tests.xctest"; 314 | remoteRef = 3B1B09301E47B3380060A062 /* PBXContainerItemProxy */; 315 | sourceTree = BUILT_PRODUCTS_DIR; 316 | }; 317 | 3B1B09331E47B3380060A062 /* Alamofire.framework */ = { 318 | isa = PBXReferenceProxy; 319 | fileType = wrapper.framework; 320 | path = Alamofire.framework; 321 | remoteRef = 3B1B09321E47B3380060A062 /* PBXContainerItemProxy */; 322 | sourceTree = BUILT_PRODUCTS_DIR; 323 | }; 324 | /* End PBXReferenceProxy section */ 325 | 326 | /* Begin PBXResourcesBuildPhase section */ 327 | 3B068AF31B34A21E00F27CBF /* Resources */ = { 328 | isa = PBXResourcesBuildPhase; 329 | buildActionMask = 2147483647; 330 | files = ( 331 | 3B068B001B34A21E00F27CBF /* Main.storyboard in Resources */, 332 | 3B068B051B34A21E00F27CBF /* LaunchScreen.xib in Resources */, 333 | 3B068B021B34A21E00F27CBF /* Images.xcassets in Resources */, 334 | ); 335 | runOnlyForDeploymentPostprocessing = 0; 336 | }; 337 | 3B068B081B34A21E00F27CBF /* Resources */ = { 338 | isa = PBXResourcesBuildPhase; 339 | buildActionMask = 2147483647; 340 | files = ( 341 | ); 342 | runOnlyForDeploymentPostprocessing = 0; 343 | }; 344 | /* End PBXResourcesBuildPhase section */ 345 | 346 | /* Begin PBXSourcesBuildPhase section */ 347 | 3B068AF11B34A21E00F27CBF /* Sources */ = { 348 | isa = PBXSourcesBuildPhase; 349 | buildActionMask = 2147483647; 350 | files = ( 351 | 3B068AFD1B34A21E00F27CBF /* ViewController.swift in Sources */, 352 | 3B4BF0091DB1F60500F3CBD0 /* QueryString.swift in Sources */, 353 | 3BE25E321B9C8A70008705F6 /* CouchDB.swift in Sources */, 354 | 3B046B181B9573480090B77C /* MyDocument.swift in Sources */, 355 | 3B068AFB1B34A21E00F27CBF /* AppDelegate.swift in Sources */, 356 | ); 357 | runOnlyForDeploymentPostprocessing = 0; 358 | }; 359 | 3B068B061B34A21E00F27CBF /* Sources */ = { 360 | isa = PBXSourcesBuildPhase; 361 | buildActionMask = 2147483647; 362 | files = ( 363 | 3B068B111B34A21E00F27CBF /* swift_couchdbTests.swift in Sources */, 364 | ); 365 | runOnlyForDeploymentPostprocessing = 0; 366 | }; 367 | /* End PBXSourcesBuildPhase section */ 368 | 369 | /* Begin PBXTargetDependency section */ 370 | 3B068B0C1B34A21E00F27CBF /* PBXTargetDependency */ = { 371 | isa = PBXTargetDependency; 372 | target = 3B068AF41B34A21E00F27CBF /* swift-couchdb */; 373 | targetProxy = 3B068B0B1B34A21E00F27CBF /* PBXContainerItemProxy */; 374 | }; 375 | /* End PBXTargetDependency section */ 376 | 377 | /* Begin PBXVariantGroup section */ 378 | 3B068AFE1B34A21E00F27CBF /* Main.storyboard */ = { 379 | isa = PBXVariantGroup; 380 | children = ( 381 | 3B068AFF1B34A21E00F27CBF /* Base */, 382 | ); 383 | name = Main.storyboard; 384 | sourceTree = ""; 385 | }; 386 | 3B068B031B34A21E00F27CBF /* LaunchScreen.xib */ = { 387 | isa = PBXVariantGroup; 388 | children = ( 389 | 3B068B041B34A21E00F27CBF /* Base */, 390 | ); 391 | name = LaunchScreen.xib; 392 | sourceTree = ""; 393 | }; 394 | /* End PBXVariantGroup section */ 395 | 396 | /* Begin XCBuildConfiguration section */ 397 | 3B068B121B34A21E00F27CBF /* Debug */ = { 398 | isa = XCBuildConfiguration; 399 | buildSettings = { 400 | ALWAYS_SEARCH_USER_PATHS = NO; 401 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 402 | CLANG_CXX_LIBRARY = "libc++"; 403 | CLANG_ENABLE_MODULES = YES; 404 | CLANG_ENABLE_OBJC_ARC = YES; 405 | CLANG_WARN_BOOL_CONVERSION = YES; 406 | CLANG_WARN_CONSTANT_CONVERSION = YES; 407 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 408 | CLANG_WARN_EMPTY_BODY = YES; 409 | CLANG_WARN_ENUM_CONVERSION = YES; 410 | CLANG_WARN_INFINITE_RECURSION = YES; 411 | CLANG_WARN_INT_CONVERSION = YES; 412 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 413 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 414 | CLANG_WARN_UNREACHABLE_CODE = YES; 415 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 416 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 417 | COPY_PHASE_STRIP = NO; 418 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 419 | ENABLE_STRICT_OBJC_MSGSEND = YES; 420 | ENABLE_TESTABILITY = YES; 421 | GCC_C_LANGUAGE_STANDARD = gnu99; 422 | GCC_DYNAMIC_NO_PIC = NO; 423 | GCC_NO_COMMON_BLOCKS = YES; 424 | GCC_OPTIMIZATION_LEVEL = 0; 425 | GCC_PREPROCESSOR_DEFINITIONS = ( 426 | "DEBUG=1", 427 | "$(inherited)", 428 | ); 429 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 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 = 8.3; 437 | MTL_ENABLE_DEBUG_INFO = YES; 438 | ONLY_ACTIVE_ARCH = YES; 439 | SDKROOT = iphoneos; 440 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 441 | TARGETED_DEVICE_FAMILY = "1,2"; 442 | }; 443 | name = Debug; 444 | }; 445 | 3B068B131B34A21E00F27CBF /* Release */ = { 446 | isa = XCBuildConfiguration; 447 | buildSettings = { 448 | ALWAYS_SEARCH_USER_PATHS = NO; 449 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 450 | CLANG_CXX_LIBRARY = "libc++"; 451 | CLANG_ENABLE_MODULES = YES; 452 | CLANG_ENABLE_OBJC_ARC = YES; 453 | CLANG_WARN_BOOL_CONVERSION = YES; 454 | CLANG_WARN_CONSTANT_CONVERSION = YES; 455 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 456 | CLANG_WARN_EMPTY_BODY = YES; 457 | CLANG_WARN_ENUM_CONVERSION = YES; 458 | CLANG_WARN_INFINITE_RECURSION = YES; 459 | CLANG_WARN_INT_CONVERSION = YES; 460 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 461 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 462 | CLANG_WARN_UNREACHABLE_CODE = YES; 463 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 464 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 465 | COPY_PHASE_STRIP = NO; 466 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 467 | ENABLE_NS_ASSERTIONS = NO; 468 | ENABLE_STRICT_OBJC_MSGSEND = YES; 469 | GCC_C_LANGUAGE_STANDARD = gnu99; 470 | GCC_NO_COMMON_BLOCKS = YES; 471 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 472 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 473 | GCC_WARN_UNDECLARED_SELECTOR = YES; 474 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 475 | GCC_WARN_UNUSED_FUNCTION = YES; 476 | GCC_WARN_UNUSED_VARIABLE = YES; 477 | IPHONEOS_DEPLOYMENT_TARGET = 8.3; 478 | MTL_ENABLE_DEBUG_INFO = NO; 479 | SDKROOT = iphoneos; 480 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 481 | TARGETED_DEVICE_FAMILY = "1,2"; 482 | VALIDATE_PRODUCT = YES; 483 | }; 484 | name = Release; 485 | }; 486 | 3B068B151B34A21E00F27CBF /* Debug */ = { 487 | isa = XCBuildConfiguration; 488 | buildSettings = { 489 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 490 | INFOPLIST_FILE = "swift-couchdb/Info.plist"; 491 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 492 | PRODUCT_BUNDLE_IDENTIFIER = "zemirco.$(PRODUCT_NAME:rfc1034identifier)"; 493 | PRODUCT_NAME = "$(TARGET_NAME)"; 494 | SWIFT_VERSION = 3.0; 495 | }; 496 | name = Debug; 497 | }; 498 | 3B068B161B34A21E00F27CBF /* Release */ = { 499 | isa = XCBuildConfiguration; 500 | buildSettings = { 501 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 502 | INFOPLIST_FILE = "swift-couchdb/Info.plist"; 503 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 504 | PRODUCT_BUNDLE_IDENTIFIER = "zemirco.$(PRODUCT_NAME:rfc1034identifier)"; 505 | PRODUCT_NAME = "$(TARGET_NAME)"; 506 | SWIFT_VERSION = 3.0; 507 | }; 508 | name = Release; 509 | }; 510 | 3B068B181B34A21E00F27CBF /* Debug */ = { 511 | isa = XCBuildConfiguration; 512 | buildSettings = { 513 | BUNDLE_LOADER = "$(TEST_HOST)"; 514 | FRAMEWORK_SEARCH_PATHS = ( 515 | "$(SDKROOT)/Developer/Library/Frameworks", 516 | "$(inherited)", 517 | ); 518 | GCC_PREPROCESSOR_DEFINITIONS = ( 519 | "DEBUG=1", 520 | "$(inherited)", 521 | ); 522 | INFOPLIST_FILE = "swift-couchdbTests/Info.plist"; 523 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 524 | PRODUCT_BUNDLE_IDENTIFIER = "zemirco.$(PRODUCT_NAME:rfc1034identifier)"; 525 | PRODUCT_NAME = "$(TARGET_NAME)"; 526 | SWIFT_VERSION = 3.0; 527 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/swift-couchdb.app/swift-couchdb"; 528 | }; 529 | name = Debug; 530 | }; 531 | 3B068B191B34A21E00F27CBF /* Release */ = { 532 | isa = XCBuildConfiguration; 533 | buildSettings = { 534 | BUNDLE_LOADER = "$(TEST_HOST)"; 535 | FRAMEWORK_SEARCH_PATHS = ( 536 | "$(SDKROOT)/Developer/Library/Frameworks", 537 | "$(inherited)", 538 | ); 539 | INFOPLIST_FILE = "swift-couchdbTests/Info.plist"; 540 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 541 | PRODUCT_BUNDLE_IDENTIFIER = "zemirco.$(PRODUCT_NAME:rfc1034identifier)"; 542 | PRODUCT_NAME = "$(TARGET_NAME)"; 543 | SWIFT_VERSION = 3.0; 544 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/swift-couchdb.app/swift-couchdb"; 545 | }; 546 | name = Release; 547 | }; 548 | /* End XCBuildConfiguration section */ 549 | 550 | /* Begin XCConfigurationList section */ 551 | 3B068AF01B34A21E00F27CBF /* Build configuration list for PBXProject "swift-couchdb" */ = { 552 | isa = XCConfigurationList; 553 | buildConfigurations = ( 554 | 3B068B121B34A21E00F27CBF /* Debug */, 555 | 3B068B131B34A21E00F27CBF /* Release */, 556 | ); 557 | defaultConfigurationIsVisible = 0; 558 | defaultConfigurationName = Release; 559 | }; 560 | 3B068B141B34A21E00F27CBF /* Build configuration list for PBXNativeTarget "swift-couchdb" */ = { 561 | isa = XCConfigurationList; 562 | buildConfigurations = ( 563 | 3B068B151B34A21E00F27CBF /* Debug */, 564 | 3B068B161B34A21E00F27CBF /* Release */, 565 | ); 566 | defaultConfigurationIsVisible = 0; 567 | defaultConfigurationName = Release; 568 | }; 569 | 3B068B171B34A21E00F27CBF /* Build configuration list for PBXNativeTarget "swift-couchdbTests" */ = { 570 | isa = XCConfigurationList; 571 | buildConfigurations = ( 572 | 3B068B181B34A21E00F27CBF /* Debug */, 573 | 3B068B191B34A21E00F27CBF /* Release */, 574 | ); 575 | defaultConfigurationIsVisible = 0; 576 | defaultConfigurationName = Release; 577 | }; 578 | /* End XCConfigurationList section */ 579 | }; 580 | rootObject = 3B068AED1B34A21E00F27CBF /* Project object */; 581 | } 582 | -------------------------------------------------------------------------------- /swift-couchdb.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /swift-couchdb.xcodeproj/project.xcworkspace/xcshareddata/swift-couchdb.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 2F799FC9-C0AB-4634-B472-46C8ACED133F 9 | IDESourceControlProjectName 10 | swift-couchdb 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 02F4FDB20D0E78E4168FDE7131FBED42485EBD9E 14 | github.com:zemirco/swift-couchdb.git 15 | 16 | IDESourceControlProjectPath 17 | swift-couchdb.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 02F4FDB20D0E78E4168FDE7131FBED42485EBD9E 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | github.com:zemirco/swift-couchdb.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | 02F4FDB20D0E78E4168FDE7131FBED42485EBD9E 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 02F4FDB20D0E78E4168FDE7131FBED42485EBD9E 36 | IDESourceControlWCCName 37 | swift-couchdb 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /swift-couchdb.xcodeproj/project.xcworkspace/xcshareddata/swift-couchdb.xcscmblueprint: -------------------------------------------------------------------------------- 1 | { 2 | "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "02F4FDB20D0E78E4168FDE7131FBED42485EBD9E", 3 | "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { 4 | 5 | }, 6 | "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { 7 | "02F4FDB20D0E78E4168FDE7131FBED42485EBD9E" : 0, 8 | "67620B5EFA902936DF04070AF595B76AB0333747" : 9223372036854775807 9 | }, 10 | "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "2F799FC9-C0AB-4634-B472-46C8ACED133F", 11 | "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { 12 | "02F4FDB20D0E78E4168FDE7131FBED42485EBD9E" : "swift-couchdb\/", 13 | "67620B5EFA902936DF04070AF595B76AB0333747" : "swift-couchdb\/Alamofire\/" 14 | }, 15 | "DVTSourceControlWorkspaceBlueprintNameKey" : "swift-couchdb", 16 | "DVTSourceControlWorkspaceBlueprintVersion" : 204, 17 | "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "swift-couchdb.xcodeproj", 18 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ 19 | { 20 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:zemirco\/swift-couchdb.git", 21 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 22 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "02F4FDB20D0E78E4168FDE7131FBED42485EBD9E" 23 | }, 24 | { 25 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/Alamofire\/Alamofire.git", 26 | "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", 27 | "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "67620B5EFA902936DF04070AF595B76AB0333747" 28 | } 29 | ] 30 | } -------------------------------------------------------------------------------- /swift-couchdb.xcodeproj/project.xcworkspace/xcuserdata/zemirco.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zemirco/swift-couchdb/60aca27435b18fb1a0132edb9f106d0630c63801/swift-couchdb.xcodeproj/project.xcworkspace/xcuserdata/zemirco.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /swift-couchdb.xcodeproj/xcshareddata/xcschemes/swift-couchdb.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 78 | 80 | 86 | 87 | 88 | 89 | 90 | 91 | 97 | 99 | 105 | 106 | 107 | 108 | 110 | 111 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /swift-couchdb.xcodeproj/xcuserdata/zemirco.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /swift-couchdb.xcodeproj/xcuserdata/zemirco.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | swift-couchdb.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 3B068AF41B34A21E00F27CBF 16 | 17 | primary 18 | 19 | 20 | 3B068B091B34A21E00F27CBF 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /swift-couchdb/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // swift-couchdb 4 | // 5 | // Created by Mirco Zeiss on 6/19/15. 6 | // Copyright (c) 2015 zemirco. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /swift-couchdb/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /swift-couchdb/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 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /swift-couchdb/CouchDB.swift: -------------------------------------------------------------------------------- 1 | 2 | import Alamofire 3 | 4 | open class CouchDB { 5 | 6 | fileprivate var url: String 7 | fileprivate var headers: [String: String]? 8 | 9 | public init(url: String, name: String?, password: String?) { 10 | self.url = url.hasSuffix("/") ? url : "\(url)/" 11 | if let name = name, let password = password { 12 | let auth = "\(name):\(password)" 13 | let data = auth.data(using: String.Encoding.utf8) 14 | let base = data!.base64EncodedString(options: []) 15 | self.headers = [ 16 | "Authorization": "Basic \(base)" 17 | ] 18 | } 19 | } 20 | 21 | public init(url: String, cookie: HTTPCookie) { 22 | self.url = url.hasSuffix("/") ? url : "\(url)/" 23 | Alamofire.SessionManager.default.session.configuration.httpCookieStorage?.setCookie(cookie) 24 | } 25 | 26 | /** 27 | * Info 28 | * 29 | * http://docs.couchdb.org/en/1.6.1/api/server/common.html#get-- 30 | */ 31 | public struct HTTPInfoResponse { 32 | public var couchdb: String! 33 | public var uuid: String! 34 | public var version: String! 35 | 36 | public init(data: Any) { 37 | if let d = data as? [String: Any] { 38 | if let 39 | couchdb = d["couchdb"] as? String, 40 | let uuid = d["uuid"] as? String, 41 | let version = d["version"] as? String { 42 | self.couchdb = couchdb 43 | self.uuid = uuid 44 | self.version = version 45 | } 46 | } 47 | } 48 | } 49 | 50 | public enum InfoResponse { 51 | case success(DataResponse, HTTPInfoResponse) 52 | case error(Error) 53 | } 54 | 55 | open func info(_ done: @escaping (InfoResponse) -> Void) { 56 | Alamofire.request(self.url, headers: self.headers).validate().responseJSON { response in 57 | switch response.result { 58 | case .failure(let error): 59 | done(.error(error)) 60 | case .success: 61 | if let json = response.result.value { 62 | done(.success(response, HTTPInfoResponse(data: json))) 63 | return 64 | } 65 | } 66 | } 67 | } 68 | 69 | 70 | 71 | /** 72 | * Login 73 | * 74 | * http://docs.couchdb.org/en/latest/api/server/authn.html 75 | */ 76 | 77 | /** 78 | * POST _session response 79 | * 80 | * http://docs.couchdb.org/en/latest/api/server/authn.html#post--_session 81 | */ 82 | public struct HTTPPostSessionResponse { 83 | public var ok: Bool! 84 | public var name: String! 85 | public var roles: [String]! 86 | 87 | public init(data: Any) { 88 | if let dict = data as? [String: Any] { 89 | if let 90 | ok = dict["ok"] as? Bool, 91 | let name = dict["name"] as? String, 92 | let roles = dict["roles"] as? [String] { 93 | self.ok = ok 94 | self.name = name 95 | self.roles = roles 96 | } 97 | } 98 | } 99 | } 100 | 101 | public enum LoginResponse { 102 | case success(DataResponse, HTTPPostSessionResponse) 103 | case error(Error) 104 | } 105 | 106 | open func login(_ name: String, password: String, done: @escaping (LoginResponse) -> Void) { 107 | let data = [ 108 | "name": name, 109 | "password": password 110 | ] 111 | Alamofire.request("\(self.url)_session", method: .post, parameters: data, encoding: JSONEncoding.default, headers: self.headers).validate().responseJSON { response in 112 | switch response.result { 113 | case .failure(let error): 114 | done(.error(error)) 115 | case .success: 116 | if let json = response.result.value { 117 | done(.success(response, HTTPPostSessionResponse(data: json))) 118 | return 119 | } 120 | } 121 | } 122 | } 123 | 124 | 125 | 126 | /** 127 | * Get session 128 | * 129 | * http://docs.couchdb.org/en/latest/api/server/authn.html#get--_session 130 | */ 131 | 132 | // http://docs.couchdb.org/en/latest/json-structure.html#user-context-object 133 | public struct UserContext { 134 | public var name: String! 135 | public var roles: [String]! 136 | 137 | public init(data: Any) { 138 | if let d = data as? [String: Any] { 139 | if let 140 | name = d["name"] as? String, 141 | let roles = d["roles"] as? [String] { 142 | self.name = name 143 | self.roles = roles 144 | } 145 | } 146 | } 147 | } 148 | 149 | public struct HTTPGetSessionResponseInfo { 150 | public var authenticated: String! 151 | public var authentication_db: String! 152 | public var authentication_handlers: [String]! 153 | 154 | public init(data: Any) { 155 | if let d = data as? [String: Any] { 156 | if let 157 | authenticated = d["authenticated"] as? String, 158 | let authentication_db = d["authentication_db"] as? String, 159 | let authentication_handlers = d["authentication_handlers"] as? [String] { 160 | self.authenticated = authenticated 161 | self.authentication_db = authentication_db 162 | self.authentication_handlers = authentication_handlers 163 | } 164 | 165 | } 166 | } 167 | } 168 | 169 | public struct HTTPGetSessionResponse { 170 | public var info: HTTPGetSessionResponseInfo! 171 | public var ok: Bool! 172 | public var userCtx: UserContext! 173 | 174 | public init(data: Any) { 175 | if let d = data as? [String: Any] { 176 | if let 177 | info = d["info"] as? [String: Any], 178 | let ok = d["ok"] as? Bool, 179 | let userCtx = d["userCtx"] as? [String: Any] { 180 | self.info = HTTPGetSessionResponseInfo(data: info) 181 | self.ok = ok 182 | self.userCtx = UserContext(data: userCtx) 183 | } 184 | } 185 | } 186 | } 187 | 188 | public enum GetSessionResponse { 189 | case success(DataResponse, HTTPGetSessionResponse) 190 | case error(Error) 191 | } 192 | 193 | open func getSession(_ done: @escaping (GetSessionResponse) -> Void) { 194 | Alamofire.request("\(self.url)_session", headers: self.headers).validate().responseJSON { response in 195 | switch response.result { 196 | case .failure(let error): 197 | done(.error(error)) 198 | case .success: 199 | if let json = response.result.value { 200 | done(.success(response, HTTPGetSessionResponse(data: json))) 201 | return 202 | } 203 | } 204 | } 205 | } 206 | 207 | 208 | 209 | /** 210 | * Logout 211 | * 212 | * http://docs.couchdb.org/en/latest/api/server/authn.html#delete--_session 213 | */ 214 | public struct HTTPDeleteSessionResponse { 215 | public var ok: Bool! 216 | 217 | public init(data: Any) { 218 | if let d = data as? [String: Any] { 219 | if let ok = d["ok"] as? Bool { 220 | self.ok = ok 221 | } 222 | } 223 | } 224 | } 225 | 226 | public enum LogoutResponse { 227 | case success(DataResponse, HTTPDeleteSessionResponse) 228 | case error(Error) 229 | } 230 | 231 | open func logout(_ done: @escaping (LogoutResponse) -> Void) { 232 | Alamofire.request("\(self.url)_session", method: .delete, headers: self.headers).validate().responseJSON { response in 233 | switch response.result { 234 | case .failure(let error): 235 | done(.error(error)) 236 | case .success: 237 | if let json = response.result.value { 238 | done(.success(response, HTTPDeleteSessionResponse(data: json))) 239 | return 240 | } 241 | } 242 | } 243 | } 244 | 245 | 246 | 247 | /** 248 | * Create database 249 | * 250 | * http://docs.couchdb.org/en/latest/api/database/common.html#put--db 251 | */ 252 | 253 | public struct HTTPPutCreateSuccess { 254 | public var ok: Bool! 255 | 256 | public init(data: Any) { 257 | if let dict = data as? [String: Any] { 258 | if 259 | let ok = dict["ok"] as? Bool { 260 | self.ok = ok 261 | } 262 | } 263 | } 264 | } 265 | 266 | public enum CreateDatabaseResponse { 267 | case success(DataResponse, HTTPPutCreateSuccess) 268 | case error(Error) 269 | } 270 | 271 | open func createDatabase(_ database: String, done: @escaping (CreateDatabaseResponse) -> Void) { 272 | Alamofire.request("\(self.url)\(database)", method: .put, headers: self.headers).validate().responseJSON { response in 273 | switch response.result { 274 | case .failure(let error): 275 | done(.error(error)) 276 | case .success: 277 | if let json = response.result.value { 278 | done(.success(response, HTTPPutCreateSuccess(data: json))) 279 | return 280 | } 281 | } 282 | } 283 | } 284 | 285 | 286 | 287 | /** 288 | * Delete database 289 | * 290 | * http://docs.couchdb.org/en/latest/api/database/common.html#delete--db 291 | */ 292 | 293 | public struct HTTPDeleteResponse { 294 | public var ok: Bool! 295 | 296 | public init(data: Any) { 297 | if let dict = data as? [String: Any] { 298 | if let ok = dict["ok"] as? Bool { 299 | self.ok = ok 300 | } 301 | } 302 | } 303 | } 304 | 305 | public enum DeleteDatabaseReponse { 306 | case success(DataResponse, HTTPDeleteResponse) 307 | case error(Error) 308 | } 309 | 310 | open func deleteDatabase(_ database: String, done: @escaping (DeleteDatabaseReponse) -> Void) { 311 | Alamofire.request("\(self.url)\(database)", method: .delete, headers: self.headers).validate().responseJSON { response in 312 | switch response.result { 313 | case .failure(let error): 314 | done(.error(error)) 315 | case .success: 316 | if let json = response.result.value { 317 | done(.success(response, HTTPDeleteResponse(data: json))) 318 | return 319 | } 320 | } 321 | 322 | } 323 | } 324 | 325 | 326 | 327 | /** 328 | * Create user 329 | */ 330 | 331 | /** 332 | * User struct 333 | * 334 | * http://docs.couchdb.org/en/latest/intro/security.html#creating-new-user 335 | */ 336 | public struct User { 337 | public var name: String 338 | public var password: String 339 | public var roles: [String] 340 | fileprivate let type: String = "user" 341 | 342 | public init(name: String, password: String, roles: [String]) { 343 | self.name = name 344 | self.password = password 345 | self.roles = roles 346 | } 347 | 348 | public func serialize() -> [String: Any] { 349 | var dict = [String: Any]() 350 | dict["name"] = name as String? 351 | dict["password"] = password as String? 352 | dict["roles"] = roles as [String]? 353 | dict["type"] = type as String? 354 | return dict 355 | } 356 | } 357 | 358 | /** 359 | * Create user in db 360 | */ 361 | open func createUser(_ user: User, done: @escaping (Database.PostResponse) -> Void) { 362 | let data = user.serialize() 363 | Alamofire.request("\(self.url)_users/org.couchdb.user:\(user.name)", method: .put, parameters: data, encoding: JSONEncoding.default, headers: self.headers).validate().responseJSON { response in 364 | switch response.result { 365 | case .failure(let error): 366 | done(.error(error)) 367 | case .success: 368 | if let json = response.result.value { 369 | done(.success(response, Database.HTTPPostDatabaseReponse(data: json))) 370 | return 371 | } 372 | } 373 | } 374 | } 375 | 376 | 377 | 378 | /** 379 | * Use database 380 | */ 381 | open func use(_ name: String) -> Database { 382 | return Database(url: "\(self.url)\(name)", headers: self.headers) 383 | } 384 | 385 | 386 | 387 | /** 388 | * Document 389 | */ 390 | open class Document { 391 | 392 | open var dictionary = [String: Any]() 393 | open var _id: String? 394 | open var _rev: String? 395 | 396 | public init(_id: String?, _rev: String?) { 397 | self._id = _id 398 | self._rev = _rev 399 | } 400 | 401 | public init(data: [String: Any]) { 402 | if let 403 | _id = data["_id"] as? String, 404 | let _rev = data["_rev"] as? String { 405 | self._id = _id 406 | self._rev = _rev 407 | } 408 | } 409 | 410 | open func serialize() -> [String: Any] { 411 | self.dictionary["_id"] = self._id as String? 412 | self.dictionary["_rev"] = self._rev as String? 413 | return self.dictionary 414 | } 415 | } 416 | 417 | 418 | 419 | /** 420 | * Design document 421 | */ 422 | open class DesignDocument: Document { 423 | 424 | open let language: String = "javascript" 425 | open var views: [String: DesignDocumentView] 426 | 427 | public init(_id: String?, _rev: String?, views: [String: DesignDocumentView]) { 428 | self.views = views 429 | super.init(_id: "_design/\(_id!)", _rev: _rev) 430 | } 431 | 432 | open override func serialize() -> [String : Any] { 433 | self.dictionary["language"] = language as String? 434 | var wrapper = [String: Any]() 435 | for (key, value) in self.views { 436 | var _views = ["map": value.map] 437 | if let reduce = value.reduce { 438 | _views["reduce"] = reduce 439 | } 440 | wrapper[key] = _views 441 | } 442 | self.dictionary["views"] = wrapper 443 | return super.serialize() 444 | } 445 | 446 | } 447 | 448 | 449 | 450 | /** 451 | * View 452 | */ 453 | open class DesignDocumentView { 454 | open var map: String 455 | open var reduce: String? 456 | 457 | public init(map: String, reduce: String?) { 458 | self.map = map 459 | self.reduce = reduce 460 | } 461 | 462 | } 463 | 464 | 465 | 466 | /** 467 | * Query params 468 | * 469 | * http://docs.couchdb.org/en/latest/api/ddoc/views.html#get--db-_design-ddoc-_view-view 470 | */ 471 | open class QueryParameters: QueryString { 472 | 473 | open var conflicts: Bool? 474 | open var descending: Bool? 475 | open var endkey: String? 476 | open var endkey_docid: String? 477 | open var group: Bool? 478 | open var group_level: Int? 479 | open var include_docs: Bool? 480 | open var attachments: Bool? 481 | open var att_encoding_info: Bool? 482 | open var inclusive_end: Bool? 483 | open var key: String? 484 | open var keys: [String]? 485 | open var limit: Int? 486 | open var reduce: Bool? 487 | open var skip: Int? 488 | open var stale: String? 489 | open var startkey: String? 490 | open var startkey_docid: String? 491 | open var update_seq: Bool? 492 | 493 | public override init() { 494 | super.init() 495 | } 496 | 497 | } 498 | 499 | 500 | 501 | /** 502 | * Database 503 | */ 504 | open class Database { 505 | 506 | fileprivate var url: String 507 | fileprivate var headers: [String: String]? 508 | 509 | public init(url: String, headers: [String: String]?) { 510 | self.url = url.hasSuffix("/") ? url : "\(url)/" 511 | self.headers = headers 512 | } 513 | 514 | 515 | /** 516 | * Create document 517 | * 518 | * http://docs.couchdb.org/en/latest/api/database/common.html#post--db 519 | */ 520 | public struct HTTPPostDatabaseReponse { 521 | public var id: String! 522 | public var ok: Bool! 523 | public var rev: String! 524 | 525 | public init(data: Any) { 526 | if let dict = data as? [String: Any] { 527 | if 528 | let id = dict["id"] as? String, 529 | let ok = dict["ok"] as? Bool, 530 | let rev = dict["rev"] as? String { 531 | self.id = id 532 | self.ok = ok 533 | self.rev = rev 534 | } 535 | } 536 | } 537 | } 538 | 539 | public enum PostResponse { 540 | case success(DataResponse, HTTPPostDatabaseReponse) 541 | case error(Error) 542 | } 543 | 544 | open func post(_ document: Document, done: @escaping (PostResponse) -> Void) { 545 | Alamofire.request(self.url, method: .post, parameters: document.serialize(), encoding: JSONEncoding.default, headers: self.headers).validate().responseJSON { response in 546 | switch response.result { 547 | case .failure(let error): 548 | done(.error(error)) 549 | case .success: 550 | if let json = response.result.value { 551 | done(.success(response, HTTPPostDatabaseReponse(data: json))) 552 | return 553 | } 554 | } 555 | } 556 | } 557 | 558 | /** 559 | * Edit document or create new one with id 560 | * 561 | * http://docs.couchdb.org/en/latest/api/document/common.html#put--db-docid 562 | */ 563 | open func put(_ document: Document, done: @escaping (PostResponse) -> Void) { 564 | Alamofire.request("\(self.url)\(document._id!)", method: .put, parameters: document.serialize(), encoding: JSONEncoding.default, headers: self.headers).validate().responseJSON { response in 565 | switch response.result { 566 | case .failure(let error): 567 | done(.error(error)) 568 | case .success: 569 | if let json = response.result.value { 570 | done(.success(response, HTTPPostDatabaseReponse(data: json))) 571 | return 572 | } 573 | } 574 | } 575 | } 576 | 577 | 578 | 579 | /** 580 | * Delete document 581 | * 582 | * http://docs.couchdb.org/en/latest/api/document/common.html#delete--db-docid 583 | */ 584 | open func delete(_ document: Document, done: @escaping (PostResponse) -> Void) { 585 | Alamofire.request("\(self.url)\(document._id!)?rev=\(document._rev!)", method: .delete, headers: self.headers).validate().responseJSON { response in 586 | switch response.result { 587 | case .failure(let error): 588 | done(.error(error)) 589 | case .success: 590 | if let json = response.result.value { 591 | done(.success(response, HTTPPostDatabaseReponse(data: json))) 592 | return 593 | } 594 | } 595 | } 596 | } 597 | 598 | 599 | 600 | /** 601 | * Get document 602 | * 603 | * http://docs.couchdb.org/en/latest/api/document/common.html#get--db-docid 604 | */ 605 | public enum GetResponse { 606 | case success(DataResponse, Any) 607 | case error(Error) 608 | } 609 | 610 | 611 | open func get(_ id: String, done: @escaping (GetResponse) -> Void) { 612 | Alamofire.request("\(self.url)\(id)", headers: self.headers).validate().responseJSON { response in 613 | switch response.result { 614 | case .failure(let error): 615 | done(.error(error)) 616 | case .success: 617 | if let json = response.result.value { 618 | done(.success(response, json)) 619 | return 620 | } 621 | } 622 | } 623 | } 624 | 625 | 626 | 627 | /** 628 | * Create multiple documents with a single request 629 | * 630 | * http://docs.couchdb.org/en/latest/api/database/bulk-api.html 631 | */ 632 | public struct HTTPBulkResponse { 633 | public var id: String! 634 | public var rev: String! 635 | public var error: String? 636 | public var reason: String? 637 | 638 | public init(data: Any) { 639 | if let dict = data as? [String: Any] { 640 | if 641 | let id = dict["id"] as? String, 642 | let rev = dict["rev"] as? String { 643 | self.id = id 644 | self.rev = rev 645 | } 646 | if let error = dict["error"] as? String { 647 | self.error = error 648 | } 649 | if let reason = dict["reason"] as? String { 650 | self.reason = reason 651 | } 652 | } 653 | } 654 | 655 | } 656 | 657 | public enum BulkResponse { 658 | case success(DataResponse, [HTTPBulkResponse]) 659 | case error(Error) 660 | } 661 | 662 | open func bulk(_ documents: [Document], done: @escaping (BulkResponse) -> Void) { 663 | let docs = documents.map() { $0.serialize() } 664 | let data = [ 665 | "docs": docs 666 | ] 667 | Alamofire.request("\(self.url)_bulk_docs", method: .post, parameters: data, encoding: JSONEncoding.default, headers: self.headers).validate().responseJSON { response in 668 | switch response.result { 669 | case .failure(let error): 670 | done(.error(error)) 671 | case .success: 672 | if let json = response.result.value { 673 | if let data = json as? [Any] { 674 | let arr = data.map() { HTTPBulkResponse(data: $0) } 675 | done(.success(response, arr)) 676 | } 677 | } 678 | } 679 | } 680 | } 681 | 682 | 683 | 684 | /** 685 | * Use certain view (design document) 686 | */ 687 | open func view(_ name: String) -> View { 688 | return View(url: "\(self.url)_design/\(name)/", headers: self.headers) 689 | } 690 | 691 | } 692 | 693 | 694 | 695 | /** 696 | * View 697 | */ 698 | open class View { 699 | 700 | /** 701 | * http://docs.couchdb.org/en/latest/api/ddoc/views.html#get--db-_design-ddoc-_view-view 702 | */ 703 | public struct GETResponse { 704 | public var offset: Int! 705 | public var rows: [Row]! 706 | public var total_rows: Int! 707 | public var update_seq: Int! 708 | 709 | public init(data: Any) { 710 | if let dict = data as? [String: Any] { 711 | if 712 | let offset = dict["offset"] as? Int, 713 | let rows = dict["rows"] as? [Any], 714 | let total_rows = dict["total_rows"] as? Int { 715 | self.offset = offset 716 | self.total_rows = total_rows 717 | self.rows = [] 718 | for row in rows { 719 | self.rows.append(Row(data: row)) 720 | } 721 | } 722 | if let update_seq = dict["update_seq"] as? Int { 723 | self.update_seq = update_seq 724 | } 725 | } 726 | } 727 | } 728 | 729 | public struct Row { 730 | public var id: String! 731 | public var key: String! 732 | public var value: Any! 733 | public var doc: [String: Any]? 734 | 735 | public init(data: Any) { 736 | if let dict = data as? [String: Any] { 737 | if 738 | let id = dict["id"] as? String, 739 | let key = dict["key"] as? String { 740 | self.id = id 741 | self.key = key 742 | self.value = dict["value"] 743 | } 744 | if let doc = dict["doc"] as? [String: Any] { 745 | self.doc = doc 746 | } 747 | } 748 | } 749 | } 750 | 751 | fileprivate var url: String 752 | fileprivate var headers: [String: String]? 753 | 754 | public init(url: String, headers: [String: String]?) { 755 | self.url = url.hasSuffix("/") ? url : "\(url)/" 756 | self.headers = headers 757 | } 758 | 759 | public enum Response { 760 | case success(DataResponse, GETResponse) 761 | case error(Error) 762 | } 763 | 764 | open func get(_ name: String, query: QueryParameters, done: @escaping (Response) -> Void) { 765 | let params = query.encode().addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)! 766 | Alamofire.request("\(self.url)_view/\(name)?\(params)", headers: self.headers).validate().responseJSON { response in 767 | switch response.result { 768 | case .failure(let error): 769 | done(.error(error)) 770 | case .success: 771 | if let json = response.result.value { 772 | done(.success(response, GETResponse(data: json))) 773 | return 774 | } 775 | } 776 | } 777 | } 778 | } 779 | 780 | 781 | } 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | -------------------------------------------------------------------------------- /swift-couchdb/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /swift-couchdb/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | NSAppTransportSecurity 47 | 48 | 49 | NSAllowsArbitraryLoads 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /swift-couchdb/MyDocument.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | open class MyDocument: CouchDB.Document { 5 | 6 | open var city: String? 7 | 8 | public init(city: String, _id: String?, _rev: String?) { 9 | self.city = city 10 | super.init(_id: _id, _rev: _rev) 11 | } 12 | 13 | public override init(data: [String: Any]) { 14 | if let city = data["city"] as? String { 15 | self.city = city 16 | } 17 | super.init(data: data) 18 | } 19 | 20 | open override func serialize() -> [String: Any] { 21 | self.dictionary["city"] = self.city as AnyObject? 22 | return super.serialize() 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /swift-couchdb/QueryString.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | 5 | 6 | /** 7 | * Query string 8 | */ 9 | open class QueryString { 10 | 11 | 12 | 13 | public init() { 14 | 15 | } 16 | 17 | 18 | 19 | /** 20 | * encode 21 | */ 22 | open func encode() -> String { 23 | 24 | let mirror = Mirror(reflecting: self) 25 | var params = [String]() 26 | 27 | for (label, value) in mirror.children { 28 | 29 | if type(of: (value)) is String.Type { 30 | params.append(handleString(label!, value: value)) 31 | } 32 | 33 | else if type(of: (value)) is Bool.Type { 34 | params.append("\(label!)=\(value)") 35 | } 36 | 37 | else if type(of: (value)) is Int.Type { 38 | params.append(handleInt(label!, value: value)) 39 | } 40 | 41 | else if type(of: (value)) is [String].Type { 42 | if let arr = value as? [String] { 43 | let vals = arr.map() {"\"\($0)\""} 44 | let values = vals.joined(separator: ",") 45 | params.append("\(label!)=[\(values)]") 46 | } 47 | } 48 | 49 | else { 50 | // handle optionals 51 | let sub = Mirror(reflecting: value) 52 | 53 | if let displayStyle = sub.displayStyle { 54 | switch displayStyle { 55 | case .optional: 56 | 57 | for (subLabel, subValue) in sub.children { 58 | 59 | if let subLabel = subLabel { 60 | if subLabel == "some" { 61 | 62 | if type(of: (subValue)) is String.Type { 63 | params.append(handleString(label!, value: subValue)) 64 | } 65 | 66 | else if type(of: (subValue)) is Int.Type { 67 | params.append(handleInt(label!, value: subValue)) 68 | } 69 | 70 | else if type(of: (subValue)) is Bool.Type { 71 | params.append("\(label!)=\(subValue)") 72 | } 73 | } 74 | } 75 | 76 | } 77 | 78 | default: 79 | break 80 | } 81 | } 82 | 83 | } 84 | } 85 | 86 | return params.joined(separator: "&") 87 | 88 | } 89 | 90 | // handle String 91 | fileprivate func handleString(_ key: String, value: Any) -> String { 92 | return "\(key)=\"\(value)\"" 93 | } 94 | 95 | fileprivate func handleInt(_ key: String, value: Any) -> String { 96 | return "\(key)=\(value)" 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /swift-couchdb/ViewController.swift: -------------------------------------------------------------------------------- 1 | 2 | import UIKit 3 | 4 | //public class MyDocument: Document { 5 | // 6 | // public var city: String! 7 | // 8 | // public init(city: String, _id: String?, _rev: String?) { 9 | // self.city = city 10 | // super.init(_id: _id, _rev: _rev) 11 | // } 12 | // 13 | // public override init(data: AnyObject) { 14 | // if let city = data["city"] as? String { 15 | // self.city = city 16 | // } 17 | // super.init(data: data) 18 | // } 19 | // 20 | // public override func serialize() -> [String: AnyObject] { 21 | // self.dictionary["city"] = self.city 22 | // return super.serialize() 23 | // } 24 | // 25 | //} 26 | 27 | class ViewController: UIViewController { 28 | 29 | override func viewDidLoad() { 30 | super.viewDidLoad() 31 | // Do any additional setup after loading the view, typically from a nib. 32 | 33 | // var couchdb = CouchDB(url: "http://localhost:5984", name: nil, password: nil) 34 | 35 | // var john = CouchDB.User(name: "john", password: "secret", roles: ["awesome"]) 36 | // couchdb.createUser(john) { response in 37 | // switch response { 38 | // case .Error(let error): 39 | // println(error) 40 | // case .Success(let res): 41 | // println(res.id) 42 | // println(res.ok) 43 | // println(res.rev) 44 | // } 45 | // } 46 | 47 | // couchdb.create("tight") { response in 48 | // switch response { 49 | // case .Error(let error): 50 | // println(error) 51 | // case .Failure(let failure): 52 | // println(failure.error) 53 | // println(failure.reason) 54 | // case .Success(let response): 55 | // println(response.ok) 56 | // } 57 | // } 58 | 59 | // couchdb.delete("nice") { response in 60 | // switch response { 61 | // case .Error(let error): 62 | // println(error) 63 | // case .Success(let res): 64 | // println(res.ok) 65 | // } 66 | // } 67 | 68 | // login 69 | // couchdb.login() { response in 70 | // switch response { 71 | // case .Error(let error): 72 | // println(error) 73 | // case .Success(let response): 74 | // println(response) 75 | // println(response.name) 76 | // println(response.ok) 77 | // println(response.roles) 78 | // } 79 | // } 80 | 81 | // var database = couchdb.use("awesome") 82 | // 83 | // create document 84 | // var doc = MyDocument(city: "darmstadt", _id: "tight", _rev: nil) 85 | // var doc = MyDocument(city: "berlin", _id: nil, _rev: nil) 86 | // database.post(doc) { response in 87 | // switch response { 88 | // case .Error(let error): 89 | // println(error) 90 | // case .Success(let res): 91 | // println(res.id) 92 | // println(res.ok) 93 | // println(res.rev) 94 | // } 95 | // } 96 | 97 | // get document 98 | // var doc: MyDocument! 99 | // database.get("tight") { response in 100 | // switch response { 101 | // case .Error(let error): 102 | // println(error) 103 | // case .Success(let data): 104 | // println(data) 105 | // doc = MyDocument(data: data) 106 | // 107 | // // edit document 108 | // doc.city = "Frankfurt" 109 | // database.put(doc) { response in 110 | // switch response { 111 | // case .Error(let error): 112 | // println(error) 113 | // case .Success(let res): 114 | // println(res.id) 115 | // println(res.ok) 116 | // println(res.rev) 117 | // } 118 | // } 119 | 120 | // // delete document 121 | // database.delete(doc) { response in 122 | // switch response { 123 | // case .Error(let error): 124 | // println(error) 125 | // case .Success(let res): 126 | // println(res.id) 127 | // println(res.rev) 128 | // println(res.ok) 129 | // } 130 | // } 131 | // } 132 | // } 133 | 134 | // var citiesByName = "function(doc) {if (doc.city) {emit(doc.city)}}" 135 | // var myView = View(map: citiesByName, reduce: nil) 136 | // 137 | // var design = DesignDocument(_id: "cities", _rev: nil, views: [ 138 | // "citiesByName": myView 139 | // ]) 140 | // 141 | // database.put(design) { response in 142 | // switch response { 143 | // case .Error(let error): 144 | // println(error) 145 | // case .Success(let res): 146 | // println(res.id) 147 | // println(res.ok) 148 | // println(res.rev) 149 | // } 150 | // 151 | // } 152 | 153 | // var test = QueryParameters() 154 | // test.descending = true 155 | // test.endkey = "awesome" 156 | // test.keys = ["one", "two", "three"] 157 | // var q = test.encode() 158 | // println(q) 159 | // println(q.stringByAddingPercentEncodingWithAllowedCharacters(.URLQueryAllowedCharacterSet())!) 160 | 161 | 162 | // // query view 163 | // var view = database.view("cities") 164 | // 165 | // var params = QueryParameters() 166 | // params.limit = 3 167 | // params.descending = true 168 | // view.get("citiesByName", query: params) { response in 169 | // switch response { 170 | // case .Error(let error): 171 | // println(error) 172 | // case .Success(let res): 173 | // println(res.offset) 174 | // println(res.total_rows) 175 | // for row in res.rows { 176 | // println(row.id) 177 | // println(row.key) 178 | // } 179 | // } 180 | // } 181 | } 182 | 183 | override func didReceiveMemoryWarning() { 184 | super.didReceiveMemoryWarning() 185 | // Dispose of any resources that can be recreated. 186 | } 187 | 188 | 189 | } 190 | 191 | -------------------------------------------------------------------------------- /swift-couchdbTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /swift-couchdbTests/swift_couchdbTests.swift: -------------------------------------------------------------------------------- 1 | 2 | import UIKit 3 | import XCTest 4 | import swift_couchdb 5 | 6 | fileprivate let url = "http://localhost:5984" 7 | 8 | class swift_couchdbTests: XCTestCase { 9 | 10 | fileprivate let timeout: TimeInterval = 1 11 | fileprivate var couchdb = CouchDB(url: url, name: nil, password: nil) 12 | 13 | override func setUp() { 14 | super.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 | super.tearDown() 21 | } 22 | 23 | 24 | 25 | func testCreateDatabase() { 26 | let expectation = self.expectation(description: "create database") 27 | let name = "test-create-database" 28 | couchdb.createDatabase(name) { response in 29 | switch response { 30 | case .error(let error): 31 | XCTAssertNil(error) 32 | case .success(let response, let success): 33 | XCTAssertEqual(response.response?.statusCode, 201) 34 | XCTAssert(success.ok!) 35 | } 36 | self.couchdb.deleteDatabase(name) { _ in 37 | expectation.fulfill() 38 | } 39 | 40 | } 41 | waitForExpectations(timeout: timeout, handler: nil) 42 | } 43 | 44 | 45 | 46 | func testDeleteDatabase() { 47 | let expectation = self.expectation(description: "delete database") 48 | let name = "test-delete-database" 49 | couchdb.createDatabase(name) { _ in 50 | self.couchdb.deleteDatabase(name) { response in 51 | switch response { 52 | case .error(let error): 53 | XCTAssertNil(error) 54 | case .success(let response, let success): 55 | XCTAssertEqual(response.response?.statusCode, 200) 56 | XCTAssert(success.ok!) 57 | } 58 | expectation.fulfill() 59 | } 60 | } 61 | waitForExpectations(timeout: timeout, handler: nil) 62 | } 63 | 64 | 65 | 66 | func testCreateDocument() { 67 | let expectation = self.expectation(description: "create document") 68 | let name = "test-create-document" 69 | couchdb.createDatabase(name) { _ in 70 | let database = self.couchdb.use(name) 71 | let doc = MyDocument(city: "darmstadt", _id: "home", _rev: nil) 72 | database.post(doc) { response in 73 | switch response { 74 | case .error(let error): 75 | XCTAssertNil(error) 76 | case .success(let response, let success): 77 | XCTAssertEqual(response.response?.statusCode, 201) 78 | XCTAssert(success.ok!) 79 | } 80 | self.couchdb.deleteDatabase(name) { _ in 81 | expectation.fulfill() 82 | } 83 | } 84 | } 85 | waitForExpectations(timeout: timeout, handler: nil) 86 | } 87 | 88 | 89 | 90 | func testGetDocument() { 91 | let expectation = self.expectation(description: "get document") 92 | let name = "test-get-document" 93 | couchdb.createDatabase(name) { _ in 94 | let database = self.couchdb.use(name) 95 | let doc = MyDocument(city: "darmstadt", _id: "home", _rev: nil) 96 | database.post(doc) { _ in 97 | database.get("home") { response in 98 | switch response { 99 | case .error(let error): 100 | XCTAssertNil(error) 101 | case .success(let response, let data): 102 | XCTAssertEqual(response.response?.statusCode, 200) 103 | let doc = MyDocument(data: data as! [String : Any]) 104 | XCTAssertEqual(doc.city, "darmstadt") 105 | } 106 | self.couchdb.deleteDatabase(name) { _ in 107 | expectation.fulfill() 108 | } 109 | } 110 | 111 | } 112 | } 113 | waitForExpectations(timeout: timeout, handler: nil) 114 | } 115 | 116 | 117 | 118 | func testDeleteDocument() { 119 | let expectation = self.expectation(description: "delete document") 120 | let name = "test-delete-document" 121 | couchdb.createDatabase(name) { _ in 122 | let database = self.couchdb.use(name) 123 | let doc = MyDocument(city: "darmstadt", _id: nil, _rev: nil) 124 | database.post(doc) { res in 125 | switch res { 126 | case .error(let error): 127 | XCTAssertNil(error) 128 | case .success(let response, let success): 129 | XCTAssertEqual(response.response?.statusCode, 201) 130 | doc._id = success.id 131 | doc._rev = success.rev 132 | database.delete(doc) { success in 133 | switch success { 134 | case .error(let error): 135 | XCTAssertNil(error) 136 | case .success(let response, let success): 137 | XCTAssertEqual(response.response?.statusCode, 200) 138 | XCTAssert(success.ok!) 139 | } 140 | self.couchdb.deleteDatabase(name) { _ in 141 | expectation.fulfill() 142 | } 143 | } 144 | } 145 | } 146 | } 147 | waitForExpectations(timeout: timeout, handler: nil) 148 | } 149 | 150 | 151 | 152 | func testEditDocument() { 153 | let expectation = self.expectation(description: "edit document") 154 | let name = "test-edit-document" 155 | couchdb.createDatabase(name) { _ in 156 | let database = self.couchdb.use(name) 157 | let doc = MyDocument(city: "darmstadt", _id: "edit", _rev: nil) 158 | database.post(doc) { _ in 159 | database.get("edit") { response in 160 | switch response { 161 | case .error(let error): 162 | XCTAssertNil(error) 163 | case .success(let response, let success): 164 | XCTAssertEqual(response.response?.statusCode, 200) 165 | let docWithRev = MyDocument(data: success as! [String : Any]) 166 | docWithRev.city = "frankfurt" 167 | database.put(docWithRev) { res in 168 | switch res { 169 | case .error(let error): 170 | XCTAssertNil(error) 171 | case .success(let response, let success): 172 | XCTAssertEqual(response.response?.statusCode, 201) 173 | XCTAssert(success.ok!) 174 | } 175 | self.couchdb.deleteDatabase(name) { _ in 176 | expectation.fulfill() 177 | } 178 | } 179 | } 180 | } 181 | } 182 | } 183 | waitForExpectations(timeout: timeout, handler: nil) 184 | } 185 | 186 | 187 | 188 | func testCreateBulkDocuments() { 189 | let berlin = MyDocument(city: "berlin", _id: nil, _rev: nil) 190 | let frankfurt = MyDocument(city: "frankfurt", _id: nil, _rev: nil) 191 | let munich = MyDocument(city: "munich", _id: nil, _rev: nil) 192 | let duesseldorf = MyDocument(city: "duesseldorf", _id: nil, _rev: nil) 193 | let darmstadt = MyDocument(city: "darmstadt", _id: nil, _rev: nil) 194 | 195 | let expectation = self.expectation(description: "bulk documents") 196 | let name = "bulk-documents" 197 | 198 | couchdb.createDatabase(name) { _ in 199 | let database = self.couchdb.use(name) 200 | database.bulk([berlin, frankfurt, munich, duesseldorf, darmstadt]) { response in 201 | switch response { 202 | case .error(let error): 203 | XCTAssertNil(error) 204 | case .success(let response, let data): 205 | XCTAssertEqual(response.response?.statusCode, 201) 206 | for datum in data { 207 | XCTAssertNotNil(datum.id) 208 | } 209 | } 210 | self.couchdb.deleteDatabase(name) { _ in 211 | expectation.fulfill() 212 | } 213 | } 214 | } 215 | waitForExpectations(timeout: timeout, handler: nil) 216 | } 217 | 218 | 219 | 220 | func testCreateDesignDocument() { 221 | let expectation = self.expectation(description: "create design document") 222 | let name = "create-design-document" 223 | 224 | // create design document 225 | let map = "function(doc) { if (doc.city) { emit(doc.city) } }" 226 | let view = CouchDB.DesignDocumentView(map: map, reduce: nil) 227 | let designDocument = CouchDB.DesignDocument(_id: "cities", _rev: nil, views: [ 228 | "byName": view 229 | ]) 230 | 231 | // add document to db 232 | couchdb.createDatabase(name) { _ in 233 | let database = self.couchdb.use(name) 234 | database.put(designDocument) { response in 235 | switch response { 236 | case .error(let error): 237 | XCTAssertNil(error) 238 | case .success(let response, let success): 239 | XCTAssertEqual(response.response?.statusCode, 201) 240 | XCTAssert(success.ok!) 241 | } 242 | self.couchdb.deleteDatabase(name) { _ in 243 | expectation.fulfill() 244 | } 245 | } 246 | } 247 | 248 | waitForExpectations(timeout: timeout, handler: nil) 249 | 250 | } 251 | 252 | 253 | 254 | func testQueryView() { 255 | let expectation = self.expectation(description: "query view") 256 | let name = "test-query-view" 257 | 258 | // create design document 259 | let map = "function(doc) { if (doc.city) { emit(doc.city) } }" 260 | let view = CouchDB.DesignDocumentView(map: map, reduce: nil) 261 | let designDocument = CouchDB.DesignDocument(_id: "cities", _rev: nil, views: [ 262 | "byName": view 263 | ]) 264 | 265 | // add design document to db 266 | couchdb.createDatabase(name) { _ in 267 | let database = self.couchdb.use(name) 268 | database.put(designDocument) { _ in 269 | 270 | // add some dummy documents 271 | let berlin = MyDocument(city: "berlin", _id: nil, _rev: nil) 272 | let frankfurt = MyDocument(city: "frankfurt", _id: nil, _rev: nil) 273 | let munich = MyDocument(city: "munich", _id: nil, _rev: nil) 274 | let duesseldorf = MyDocument(city: "duesseldorf", _id: nil, _rev: nil) 275 | let darmstadt = MyDocument(city: "darmstadt", _id: nil, _rev: nil) 276 | 277 | database.bulk([berlin, frankfurt, munich, duesseldorf, darmstadt]) { _ in 278 | 279 | // query view 280 | let view = database.view("cities") 281 | let params = CouchDB.QueryParameters() 282 | params.limit = 3 283 | params.descending = true 284 | view.get("byName", query: params) { response in 285 | switch response { 286 | case .error(let error): 287 | XCTAssertNil(error) 288 | case .success(let result, let response): 289 | XCTAssertEqual(result.response?.statusCode, 200) 290 | XCTAssertEqual(response.rows.count, 3) 291 | XCTAssertEqual(response.rows[0].key, "munich") 292 | } 293 | self.couchdb.deleteDatabase(name) { _ in 294 | expectation.fulfill() 295 | } 296 | } 297 | 298 | } 299 | 300 | } 301 | } 302 | 303 | waitForExpectations(timeout: timeout, handler: nil) 304 | } 305 | 306 | 307 | 308 | func testCreateUser() { 309 | let expectation = self.expectation(description: "create user") 310 | 311 | let john = CouchDB.User(name: "john", password: "secret", roles: ["awesome"]) 312 | couchdb.createUser(john) { response in 313 | switch response { 314 | case .error(let error): 315 | XCTAssertNil(error) 316 | case .success(let response, let res): 317 | XCTAssertEqual(response.response?.statusCode, 201) 318 | XCTAssert(res.ok!) 319 | } 320 | expectation.fulfill() 321 | } 322 | 323 | waitForExpectations(timeout: timeout, handler: nil) 324 | } 325 | 326 | 327 | 328 | func testDeleteUser() { 329 | let expectation = self.expectation(description: "delete user") 330 | 331 | // create user 332 | let john = CouchDB.User(name: "john", password: "secret", roles: ["awesome"]) 333 | couchdb.createUser(john) { _ in 334 | 335 | // delete user 336 | let database = self.couchdb.use("_users") 337 | database.get("org.couchdb.user:john") { response in 338 | switch response { 339 | case .error(let error): 340 | XCTAssertNil(error) 341 | case .success(let response, let json): 342 | XCTAssertEqual(response.response?.statusCode, 200) 343 | let doc = CouchDB.Document(data: json as! [String : Any]) 344 | 345 | database.delete(doc) { res in 346 | switch res { 347 | case .error(let error): 348 | XCTAssertNil(error) 349 | case .success(let response, let success): 350 | XCTAssertEqual(response.response?.statusCode, 200) 351 | XCTAssert(success.ok!) 352 | } 353 | expectation.fulfill() 354 | } 355 | 356 | } 357 | } 358 | 359 | } 360 | 361 | waitForExpectations(timeout: timeout, handler: nil) 362 | } 363 | 364 | 365 | 366 | func testLogin() { 367 | let expectation = self.expectation(description: "login") 368 | 369 | // create user first 370 | let steve = CouchDB.User(name: "steve", password: "password", roles: ["awesome"]) 371 | couchdb.createUser(steve) { _ in 372 | 373 | // test login 374 | self.couchdb.login("steve", password: "password") { response in 375 | switch response { 376 | case .error(let error): 377 | XCTAssertNil(error) 378 | case .success(let response, let success): 379 | XCTAssertEqual(response.response?.statusCode, 200) 380 | XCTAssert(success.ok!) 381 | } 382 | 383 | // delete user 384 | let database = self.couchdb.use("_users") 385 | database.get("org.couchdb.user:steve") { response in 386 | switch response { 387 | case .error(let error): 388 | XCTAssertNil(error) 389 | case .success(let response, let json): 390 | XCTAssertEqual(response.response?.statusCode, 200) 391 | let doc = CouchDB.Document(data: json as! [String : Any]) 392 | 393 | database.delete(doc) { _ in 394 | expectation.fulfill() 395 | } 396 | } 397 | } 398 | } 399 | 400 | } 401 | 402 | waitForExpectations(timeout: timeout, handler: nil) 403 | } 404 | 405 | 406 | 407 | func testGetSession() { 408 | let expectation = self.expectation(description: "get session") 409 | 410 | // create user 411 | let wiff = CouchDB.User(name: "wiff", password: "pwd", roles: ["dog"]) 412 | couchdb.createUser(wiff) { _ in 413 | 414 | // login 415 | self.couchdb.login("wiff", password: "pwd") { _ in 416 | 417 | // get session 418 | self.couchdb.getSession() { response in 419 | 420 | switch response { 421 | case .error(let error): 422 | XCTAssertNil(error) 423 | case .success(let response, let res): 424 | XCTAssertEqual(response.response?.statusCode, 200) 425 | XCTAssertEqual(res.info.authenticated, "cookie") 426 | XCTAssertEqual(res.userCtx.roles, ["dog"]) 427 | XCTAssert(res.ok!) 428 | } 429 | 430 | // delete user 431 | let database = self.couchdb.use("_users") 432 | database.get("org.couchdb.user:wiff") { response in 433 | switch response { 434 | case .error(let error): 435 | XCTAssertNil(error) 436 | case .success(let response, let json): 437 | XCTAssertEqual(response.response?.statusCode, 200) 438 | let doc = CouchDB.Document(data: json as! [String : Any]) 439 | 440 | database.delete(doc) { _ in 441 | expectation.fulfill() 442 | } 443 | } 444 | } 445 | 446 | } 447 | 448 | } 449 | 450 | } 451 | 452 | waitForExpectations(timeout: timeout, handler: nil) 453 | } 454 | 455 | 456 | 457 | func testLogout() { 458 | let expectation = self.expectation(description: "logout") 459 | 460 | // create user 461 | let nitika = CouchDB.User(name: "nitika", password: "pwd", roles: ["dog"]) 462 | couchdb.createUser(nitika) { _ in 463 | 464 | // login 465 | self.couchdb.login("nitika", password: "pwd") { _ in 466 | 467 | // make sure user has session 468 | self.couchdb.getSession() { session in 469 | switch session { 470 | case .error(let error): 471 | XCTAssertNil(error) 472 | case .success(let response, let success): 473 | XCTAssertEqual(response.response?.statusCode, 200) 474 | XCTAssert(success.ok!) 475 | } 476 | 477 | // logout 478 | self.couchdb.logout() { response in 479 | switch response { 480 | case .error(let error): 481 | XCTAssertNil(error) 482 | case .success(let response, let res): 483 | XCTAssertEqual(response.response?.statusCode, 200) 484 | XCTAssert(res.ok!) 485 | } 486 | 487 | // delete user 488 | let database = self.couchdb.use("_users") 489 | database.get("org.couchdb.user:nitika") { response in 490 | switch response { 491 | case .error(let error): 492 | XCTAssertNil(error) 493 | case .success(let response, let json): 494 | XCTAssertEqual(response.response?.statusCode, 200) 495 | let doc = CouchDB.Document(data: json as! [String : Any]) 496 | 497 | database.delete(doc) { _ in 498 | expectation.fulfill() 499 | } 500 | } 501 | } 502 | 503 | } 504 | } 505 | 506 | 507 | } 508 | 509 | } 510 | 511 | waitForExpectations(timeout: timeout, handler: nil) 512 | } 513 | 514 | func testCookie() { 515 | let expectation = self.expectation(description: "cookie") 516 | 517 | // create user 518 | let juna = CouchDB.User(name: "juna", password: "juna", roles: ["user"]) 519 | couchdb.createUser(juna) { _ in 520 | 521 | // login to get cookie 522 | self.couchdb.login("juna", password: "juna") { response in 523 | switch response { 524 | case .error(let error): 525 | XCTAssertNil(error) 526 | case .success(let response, let success): 527 | XCTAssertEqual(response.response?.statusCode, 200) 528 | XCTAssert(success.ok!) 529 | 530 | // get cookie from response 531 | if 532 | let headerFields = response.response?.allHeaderFields as? [String: String], 533 | let uri = response.request?.url { 534 | let cookies = HTTPCookie.cookies(withResponseHeaderFields: headerFields, for: uri) 535 | let cookie = cookies[0] 536 | 537 | // create another couchdb instance without password but with cookie 538 | // auth headers are empty and therefore only cookie is used for auth 539 | let couchdb2 = CouchDB(url: url, cookie: cookie) 540 | couchdb2.getSession() { response in 541 | 542 | switch response { 543 | case .error(let error): 544 | XCTAssertNil(error) 545 | case .success(let response, let res): 546 | XCTAssertEqual(response.response?.statusCode, 200) 547 | XCTAssertEqual(res.info.authenticated, "cookie") 548 | XCTAssertEqual(res.userCtx.roles, ["user"]) 549 | XCTAssert(res.ok!) 550 | XCTAssertEqual(res.userCtx.name, "juna") 551 | } 552 | 553 | // delete user 554 | let database = self.couchdb.use("_users") 555 | database.get("org.couchdb.user:juna") { response in 556 | switch response { 557 | case .error(let error): 558 | XCTAssertNil(error) 559 | case .success(let response, let json): 560 | XCTAssertEqual(response.response?.statusCode, 200) 561 | let doc = CouchDB.Document(data: json as! [String : Any]) 562 | 563 | database.delete(doc) { _ in 564 | expectation.fulfill() 565 | } 566 | } 567 | } 568 | } 569 | } 570 | } 571 | } 572 | 573 | } 574 | waitForExpectations(timeout: timeout, handler: nil) 575 | } 576 | 577 | 578 | 579 | } 580 | --------------------------------------------------------------------------------