├── .gitignore ├── .travis.yml ├── AlgoliaSearch-Client.podspec ├── ChangeLog ├── LICENSE ├── Podfile ├── README.md ├── algoliasearch-client-objc.xcodeproj ├── project.pbxproj └── xcshareddata │ └── xcschemes │ └── travis-test.xcscheme ├── algoliasearch-client-objc.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── algoliasearch-client-objc.xccheckout ├── src ├── ASAPIClient+Network.h ├── ASAPIClient+Network.m ├── ASAPIClient.h ├── ASAPIClient.m ├── ASBrowseIterator.h ├── ASBrowseIterator.m ├── ASExpiringCache.h ├── ASExpiringCache.m ├── ASExpiringCacheItem.h ├── ASExpiringCacheItem.m ├── ASQuery.h ├── ASQuery.m ├── ASRemoteIndex.h └── ASRemoteIndex.m └── test ├── en.lproj └── InfoPlist.strings ├── test-Info.plist └── test.m /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pbxuser 3 | !default.pbxuser 4 | *.xcworkspace 5 | !default.xcworkspace 6 | xcuserdata 7 | Pods 8 | Podfile.lock 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | cache: cocoapods 3 | env: 4 | global: 5 | - secure: UiyDncG6TxTG1MLIBqAwN6K7OQZL5jI78SHJ/CQS6FydkGV8OWYEoV5l2adPx3Eq4BRdanq3FaMmX1sVzqQkCbKhUF3JU9+Dgpvo/IpYVLmKEwfDBTQv2KQacRB52KeBK9DBrhDiydjCQpzNoNeKffK5zLULaqEsq0uZnoVmfxg= 6 | - secure: SFCFdybtrtBsosLvUoEcbYmNBAihPwsXsN4hHnUoUsjxBJJXyvFurDLcnZjQJAHa3pMLeG4Gj1ELqSVHYxmN1x5sAmmObS/NpWjeTwmSSOksyKBvAHVOY/a0EWira4HvjKP6OsbOcLVkQxBuaJKmtJCGXX59pGgJXLUxNVV8dIw= 7 | before_install: 8 | - gem install cocoapods xcpretty -N 9 | install: 10 | - pod install 11 | script: 12 | - set -o pipefail 13 | - xcodebuild -workspace algoliasearch-client-objc.xcworkspace -scheme travis-test -sdk macosx test | xcpretty -c 14 | -------------------------------------------------------------------------------- /AlgoliaSearch-Client.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'AlgoliaSearch-Client' 3 | s.version = '3.7.0' 4 | s.license = 'MIT' 5 | s.summary = 'Algolia Search API Client for iOS & OS X written in Objective-C.' 6 | s.homepage = 'https://github.com/algolia/algoliasearch-client-objc' 7 | s.author = { 'Algolia' => 'contact@algolia.com' } 8 | s.source = { :git => 'https://github.com/algolia/algoliasearch-client-objc.git', :tag => s.version } 9 | 10 | s.ios.deployment_target = '6.0' 11 | s.ios.frameworks = 'MobileCoreServices', 'SystemConfiguration', 'Security' 12 | 13 | s.osx.deployment_target = '10.8' 14 | s.osx.frameworks = 'CoreServices', 'SystemConfiguration', 'Security' 15 | 16 | s.source_files = 'src/*.{h,m}' 17 | s.private_header_files = 'src/ASExpiringCache*.h' 18 | 19 | s.dependency 'AFNetworking', '~> 2.2' 20 | end 21 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | CHANGELOG 2 | 3 | 2016-02-05 3.6.4 4 | - Added support of snippet ellipsis 5 | 6 | 2015-10-16 3.6.3 7 | - Fixed ability to override index settings 8 | 9 | 2015-10-12 3.6.2 10 | - Added remove stop words query parameter 11 | - Added support of similar queries 12 | - Added advanced syntax option 13 | 14 | 2015-09-30 3.6.1 15 | * Added support of multiple bounding box for geo-search 16 | * Added support of polygon for geo-search 17 | * Added support of automatic radius computation for geo-search 18 | * Added support of disableTypoToleranceOnAttributes 19 | 20 | 2015-07-27 3.6.0 21 | * Add search cache (disabled by default) 22 | 23 | 2015-07-07 3.5.2 24 | * New browseFromCursor method 25 | * Add analyticsTags to Query 26 | 27 | 2015-07-01 3.5.1 28 | * Fix grouping 29 | 30 | 2015-07-01 3.5.0 31 | * ASQuery implements protocol NSCopying 32 | * Fix various bugs 33 | 34 | 2015-06-30 3.4.6 35 | * Added support of grouping (distinct=3 for example keep the 3 best hits for a distinct key) 36 | 37 | 2015-06-16 3.4.5 38 | * New browse method that takes a ASQuery object 39 | * Remove DSN flag 40 | 41 | 2015-05-04 3.4.4 42 | * add new parameter on the Query: setMinProximity & setHighlightingTags 43 | 44 | 2015-05-04 3.4.3 45 | * Add new methods to add/update api key 46 | * Add batch method to target multiple indices 47 | * Add strategy parameter for the multipleQueries 48 | * Add new method to generate secured api key from query parameters 49 | 50 | 2015-04-22 3.4.2 51 | * Fix issue with geo search 52 | 53 | 2015-04-10 3.4.1 54 | * Return the error message from the backend instead of a static message for 4XX 55 | 56 | 2015-04-10 3.4.0 57 | * Add new retry logic 58 | 59 | 2014-11-30 3.2.0 60 | * Switch .io to .net 61 | 62 | 2014-11-07 3.1.23 63 | * Add DSN flag 64 | 65 | 2014-10-27 3.1.22 66 | * Add extra optionalWordsMinimumMatched query parameter 67 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Algolia 4 | http://www.algolia.com/ 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | platform :osx, '10.9' 3 | workspace 'algoliasearch-client-objc' 4 | 5 | pod 'AFNetworking', '~> 2.4.0' 6 | -------------------------------------------------------------------------------- /algoliasearch-client-objc.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 590677CA18E4E38B00D2B893 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 591C934418E265C3001F1A0F /* XCTest.framework */; settings = {ATTRIBUTES = (Required, ); }; }; 11 | 590677D018E4E38B00D2B893 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 590677CE18E4E38B00D2B893 /* InfoPlist.strings */; }; 12 | 590677D218E4E38B00D2B893 /* test.m in Sources */ = {isa = PBXBuildFile; fileRef = 590677D118E4E38B00D2B893 /* test.m */; }; 13 | 5909919919EFB7FA003DA269 /* ASAPIClient+Network.m in Sources */ = {isa = PBXBuildFile; fileRef = 591C935E18E267B5001F1A0F /* ASAPIClient+Network.m */; }; 14 | 5909919A19EFB7FE003DA269 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 599EA22619ED664700FEF7E7 /* AppKit.framework */; }; 15 | 5909919C19EFB827003DA269 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 454533AE49614E8FA1210C4D /* libPods.a */; }; 16 | 591C933718E265C3001F1A0F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 591C933618E265C3001F1A0F /* Foundation.framework */; }; 17 | 591C936518E267B5001F1A0F /* ASAPIClient+Network.m in Sources */ = {isa = PBXBuildFile; fileRef = 591C935E18E267B5001F1A0F /* ASAPIClient+Network.m */; }; 18 | 591C936618E267B5001F1A0F /* ASAPIClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 591C936018E267B5001F1A0F /* ASAPIClient.m */; }; 19 | 591C936718E267B5001F1A0F /* ASQuery.m in Sources */ = {isa = PBXBuildFile; fileRef = 591C936218E267B5001F1A0F /* ASQuery.m */; }; 20 | 591C936818E267B5001F1A0F /* ASRemoteIndex.m in Sources */ = {isa = PBXBuildFile; fileRef = 591C936418E267B5001F1A0F /* ASRemoteIndex.m */; }; 21 | 592EEA9118E4F14200891427 /* libalgoliasearch-client-objc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 591C933318E265C3001F1A0F /* libalgoliasearch-client-objc.a */; settings = {ATTRIBUTES = (Required, ); }; }; 22 | 599EA22D19EFB2D700FEF7E7 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 599EA22619ED664700FEF7E7 /* AppKit.framework */; }; 23 | 59C8346C1BD1542A0058D999 /* libAFNetworking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 59C8346B1BD1542A0058D999 /* libAFNetworking.a */; }; 24 | 59C8346D1BD154410058D999 /* libAFNetworking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 59C8346B1BD1542A0058D999 /* libAFNetworking.a */; }; 25 | 5D7B33401B4BBD7B00F12D56 /* ASExpiringCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D7B333F1B4BBD7B00F12D56 /* ASExpiringCache.m */; }; 26 | 5D7B33431B4BBDEB00F12D56 /* ASExpiringCacheItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D7B33421B4BBDEB00F12D56 /* ASExpiringCacheItem.m */; }; 27 | 5D85ED221B28659A001C1C5B /* ASBrowseIterator.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D85ED211B28659A001C1C5B /* ASBrowseIterator.m */; }; 28 | 88FF96774A8D4C439B606454 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 454533AE49614E8FA1210C4D /* libPods.a */; settings = {ATTRIBUTES = (Required, ); }; }; 29 | /* End PBXBuildFile section */ 30 | 31 | /* Begin PBXContainerItemProxy section */ 32 | 590677D418E4E38C00D2B893 /* PBXContainerItemProxy */ = { 33 | isa = PBXContainerItemProxy; 34 | containerPortal = 591C932B18E265C3001F1A0F /* Project object */; 35 | proxyType = 1; 36 | remoteGlobalIDString = 591C933218E265C3001F1A0F; 37 | remoteInfo = "algoliasearch-client-objc"; 38 | }; 39 | /* End PBXContainerItemProxy section */ 40 | 41 | /* Begin PBXCopyFilesBuildPhase section */ 42 | 591C933118E265C3001F1A0F /* CopyFiles */ = { 43 | isa = PBXCopyFilesBuildPhase; 44 | buildActionMask = 2147483647; 45 | dstPath = "include/$(PRODUCT_NAME)"; 46 | dstSubfolderSpec = 16; 47 | files = ( 48 | ); 49 | runOnlyForDeploymentPostprocessing = 0; 50 | }; 51 | /* End PBXCopyFilesBuildPhase section */ 52 | 53 | /* Begin PBXFileReference section */ 54 | 454533AE49614E8FA1210C4D /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; 55 | 590677C918E4E38B00D2B893 /* test.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = test.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 56 | 590677CD18E4E38B00D2B893 /* test-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "test-Info.plist"; sourceTree = ""; }; 57 | 590677CF18E4E38B00D2B893 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 58 | 590677D118E4E38B00D2B893 /* test.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = test.m; sourceTree = ""; }; 59 | 590677D318E4E38C00D2B893 /* test-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "test-Prefix.pch"; sourceTree = ""; }; 60 | 591C933318E265C3001F1A0F /* libalgoliasearch-client-objc.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libalgoliasearch-client-objc.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 61 | 591C933618E265C3001F1A0F /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 62 | 591C934418E265C3001F1A0F /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 63 | 591C935D18E267B5001F1A0F /* ASAPIClient+Network.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASAPIClient+Network.h"; sourceTree = ""; }; 64 | 591C935E18E267B5001F1A0F /* ASAPIClient+Network.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "ASAPIClient+Network.m"; sourceTree = ""; }; 65 | 591C935F18E267B5001F1A0F /* ASAPIClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASAPIClient.h; sourceTree = ""; }; 66 | 591C936018E267B5001F1A0F /* ASAPIClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASAPIClient.m; sourceTree = ""; }; 67 | 591C936118E267B5001F1A0F /* ASQuery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASQuery.h; sourceTree = ""; }; 68 | 591C936218E267B5001F1A0F /* ASQuery.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASQuery.m; sourceTree = ""; }; 69 | 591C936318E267B5001F1A0F /* ASRemoteIndex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASRemoteIndex.h; sourceTree = ""; }; 70 | 591C936418E267B5001F1A0F /* ASRemoteIndex.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASRemoteIndex.m; sourceTree = ""; }; 71 | 599EA22119ED5E9A00FEF7E7 /* libPods-AFNetworking.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libPods-AFNetworking.a"; path = "../../../Library/Developer/Xcode/DerivedData/algoliasearch-client-objc-ezaqtrvmayymwwavbcfvoeuiphpx/Build/Products/Debug/libPods-AFNetworking.a"; sourceTree = ""; }; 72 | 599EA22619ED664700FEF7E7 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 73 | 59C8346B1BD1542A0058D999 /* libAFNetworking.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libAFNetworking.a; path = "../../../Library/Developer/Xcode/DerivedData/algoliasearch-client-objc-ezaqtrvmayymwwavbcfvoeuiphpx/Build/Products/Debug/libAFNetworking.a"; sourceTree = ""; }; 74 | 5D7B333E1B4BBD7B00F12D56 /* ASExpiringCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASExpiringCache.h; sourceTree = ""; }; 75 | 5D7B333F1B4BBD7B00F12D56 /* ASExpiringCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASExpiringCache.m; sourceTree = ""; }; 76 | 5D7B33411B4BBDEB00F12D56 /* ASExpiringCacheItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASExpiringCacheItem.h; sourceTree = ""; }; 77 | 5D7B33421B4BBDEB00F12D56 /* ASExpiringCacheItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASExpiringCacheItem.m; sourceTree = ""; }; 78 | 5D85ED201B28659A001C1C5B /* ASBrowseIterator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASBrowseIterator.h; sourceTree = ""; }; 79 | 5D85ED211B28659A001C1C5B /* ASBrowseIterator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASBrowseIterator.m; sourceTree = ""; }; 80 | 93A3C6D5C4BEC322D8180EA7 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; 81 | EE723D9FA715B3A80A9DBE58 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; 82 | /* End PBXFileReference section */ 83 | 84 | /* Begin PBXFrameworksBuildPhase section */ 85 | 590677C618E4E38B00D2B893 /* Frameworks */ = { 86 | isa = PBXFrameworksBuildPhase; 87 | buildActionMask = 2147483647; 88 | files = ( 89 | 59C8346D1BD154410058D999 /* libAFNetworking.a in Frameworks */, 90 | 5909919C19EFB827003DA269 /* libPods.a in Frameworks */, 91 | 5909919A19EFB7FE003DA269 /* AppKit.framework in Frameworks */, 92 | 592EEA9118E4F14200891427 /* libalgoliasearch-client-objc.a in Frameworks */, 93 | 590677CA18E4E38B00D2B893 /* XCTest.framework in Frameworks */, 94 | ); 95 | runOnlyForDeploymentPostprocessing = 0; 96 | }; 97 | 591C933018E265C3001F1A0F /* Frameworks */ = { 98 | isa = PBXFrameworksBuildPhase; 99 | buildActionMask = 2147483647; 100 | files = ( 101 | 59C8346C1BD1542A0058D999 /* libAFNetworking.a in Frameworks */, 102 | 88FF96774A8D4C439B606454 /* libPods.a in Frameworks */, 103 | 599EA22D19EFB2D700FEF7E7 /* AppKit.framework in Frameworks */, 104 | 591C933718E265C3001F1A0F /* Foundation.framework in Frameworks */, 105 | ); 106 | runOnlyForDeploymentPostprocessing = 0; 107 | }; 108 | /* End PBXFrameworksBuildPhase section */ 109 | 110 | /* Begin PBXGroup section */ 111 | 47BECB5F255FE4B756F895D0 /* Pods */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | EE723D9FA715B3A80A9DBE58 /* Pods.debug.xcconfig */, 115 | 93A3C6D5C4BEC322D8180EA7 /* Pods.release.xcconfig */, 116 | ); 117 | name = Pods; 118 | sourceTree = ""; 119 | }; 120 | 590677CB18E4E38B00D2B893 /* test */ = { 121 | isa = PBXGroup; 122 | children = ( 123 | 590677D118E4E38B00D2B893 /* test.m */, 124 | 590677CC18E4E38B00D2B893 /* Supporting Files */, 125 | ); 126 | path = test; 127 | sourceTree = ""; 128 | }; 129 | 590677CC18E4E38B00D2B893 /* Supporting Files */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | 590677CD18E4E38B00D2B893 /* test-Info.plist */, 133 | 590677CE18E4E38B00D2B893 /* InfoPlist.strings */, 134 | 590677D318E4E38C00D2B893 /* test-Prefix.pch */, 135 | ); 136 | name = "Supporting Files"; 137 | sourceTree = ""; 138 | }; 139 | 591C932A18E265C3001F1A0F = { 140 | isa = PBXGroup; 141 | children = ( 142 | 591C935C18E267B5001F1A0F /* src */, 143 | 590677CB18E4E38B00D2B893 /* test */, 144 | 591C933518E265C3001F1A0F /* Frameworks */, 145 | 591C933418E265C3001F1A0F /* Products */, 146 | 47BECB5F255FE4B756F895D0 /* Pods */, 147 | ); 148 | sourceTree = ""; 149 | }; 150 | 591C933418E265C3001F1A0F /* Products */ = { 151 | isa = PBXGroup; 152 | children = ( 153 | 591C933318E265C3001F1A0F /* libalgoliasearch-client-objc.a */, 154 | 590677C918E4E38B00D2B893 /* test.xctest */, 155 | ); 156 | name = Products; 157 | sourceTree = ""; 158 | }; 159 | 591C933518E265C3001F1A0F /* Frameworks */ = { 160 | isa = PBXGroup; 161 | children = ( 162 | 59C8346B1BD1542A0058D999 /* libAFNetworking.a */, 163 | 599EA22619ED664700FEF7E7 /* AppKit.framework */, 164 | 599EA22119ED5E9A00FEF7E7 /* libPods-AFNetworking.a */, 165 | 591C933618E265C3001F1A0F /* Foundation.framework */, 166 | 591C934418E265C3001F1A0F /* XCTest.framework */, 167 | 454533AE49614E8FA1210C4D /* libPods.a */, 168 | ); 169 | name = Frameworks; 170 | sourceTree = ""; 171 | }; 172 | 591C935C18E267B5001F1A0F /* src */ = { 173 | isa = PBXGroup; 174 | children = ( 175 | 591C935D18E267B5001F1A0F /* ASAPIClient+Network.h */, 176 | 591C935E18E267B5001F1A0F /* ASAPIClient+Network.m */, 177 | 591C935F18E267B5001F1A0F /* ASAPIClient.h */, 178 | 591C936018E267B5001F1A0F /* ASAPIClient.m */, 179 | 591C936118E267B5001F1A0F /* ASQuery.h */, 180 | 591C936218E267B5001F1A0F /* ASQuery.m */, 181 | 591C936318E267B5001F1A0F /* ASRemoteIndex.h */, 182 | 591C936418E267B5001F1A0F /* ASRemoteIndex.m */, 183 | 5D85ED201B28659A001C1C5B /* ASBrowseIterator.h */, 184 | 5D85ED211B28659A001C1C5B /* ASBrowseIterator.m */, 185 | 5D7B333E1B4BBD7B00F12D56 /* ASExpiringCache.h */, 186 | 5D7B333F1B4BBD7B00F12D56 /* ASExpiringCache.m */, 187 | 5D7B33411B4BBDEB00F12D56 /* ASExpiringCacheItem.h */, 188 | 5D7B33421B4BBDEB00F12D56 /* ASExpiringCacheItem.m */, 189 | ); 190 | path = src; 191 | sourceTree = ""; 192 | }; 193 | /* End PBXGroup section */ 194 | 195 | /* Begin PBXNativeTarget section */ 196 | 590677C818E4E38B00D2B893 /* test */ = { 197 | isa = PBXNativeTarget; 198 | buildConfigurationList = 590677D618E4E38C00D2B893 /* Build configuration list for PBXNativeTarget "test" */; 199 | buildPhases = ( 200 | 4705BE80F69E43FFBD0BE466 /* Check Pods Manifest.lock */, 201 | 590677C518E4E38B00D2B893 /* Sources */, 202 | 590677C618E4E38B00D2B893 /* Frameworks */, 203 | 590677C718E4E38B00D2B893 /* Resources */, 204 | 25622EFDC68B4D778F7B390C /* Copy Pods Resources */, 205 | ); 206 | buildRules = ( 207 | ); 208 | dependencies = ( 209 | 590677D518E4E38C00D2B893 /* PBXTargetDependency */, 210 | ); 211 | name = test; 212 | productName = test; 213 | productReference = 590677C918E4E38B00D2B893 /* test.xctest */; 214 | productType = "com.apple.product-type.bundle.unit-test"; 215 | }; 216 | 591C933218E265C3001F1A0F /* algoliasearch-client-objc */ = { 217 | isa = PBXNativeTarget; 218 | buildConfigurationList = 591C935618E265C3001F1A0F /* Build configuration list for PBXNativeTarget "algoliasearch-client-objc" */; 219 | buildPhases = ( 220 | D9D6816F15AB4AA2A4FC8954 /* Check Pods Manifest.lock */, 221 | 591C932F18E265C3001F1A0F /* Sources */, 222 | 591C933018E265C3001F1A0F /* Frameworks */, 223 | 591C933118E265C3001F1A0F /* CopyFiles */, 224 | EA350182CD3A49308F4218CA /* Copy Pods Resources */, 225 | ); 226 | buildRules = ( 227 | ); 228 | dependencies = ( 229 | ); 230 | name = "algoliasearch-client-objc"; 231 | productName = "algoliasearch-client-objc"; 232 | productReference = 591C933318E265C3001F1A0F /* libalgoliasearch-client-objc.a */; 233 | productType = "com.apple.product-type.library.static"; 234 | }; 235 | /* End PBXNativeTarget section */ 236 | 237 | /* Begin PBXProject section */ 238 | 591C932B18E265C3001F1A0F /* Project object */ = { 239 | isa = PBXProject; 240 | attributes = { 241 | LastUpgradeCheck = 0630; 242 | ORGANIZATIONNAME = Algolia; 243 | TargetAttributes = { 244 | 590677C818E4E38B00D2B893 = { 245 | TestTargetID = 591C933218E265C3001F1A0F; 246 | }; 247 | }; 248 | }; 249 | buildConfigurationList = 591C932E18E265C3001F1A0F /* Build configuration list for PBXProject "algoliasearch-client-objc" */; 250 | compatibilityVersion = "Xcode 3.2"; 251 | developmentRegion = English; 252 | hasScannedForEncodings = 0; 253 | knownRegions = ( 254 | en, 255 | ); 256 | mainGroup = 591C932A18E265C3001F1A0F; 257 | productRefGroup = 591C933418E265C3001F1A0F /* Products */; 258 | projectDirPath = ""; 259 | projectRoot = ""; 260 | targets = ( 261 | 591C933218E265C3001F1A0F /* algoliasearch-client-objc */, 262 | 590677C818E4E38B00D2B893 /* test */, 263 | ); 264 | }; 265 | /* End PBXProject section */ 266 | 267 | /* Begin PBXResourcesBuildPhase section */ 268 | 590677C718E4E38B00D2B893 /* Resources */ = { 269 | isa = PBXResourcesBuildPhase; 270 | buildActionMask = 2147483647; 271 | files = ( 272 | 590677D018E4E38B00D2B893 /* InfoPlist.strings in Resources */, 273 | ); 274 | runOnlyForDeploymentPostprocessing = 0; 275 | }; 276 | /* End PBXResourcesBuildPhase section */ 277 | 278 | /* Begin PBXShellScriptBuildPhase section */ 279 | 25622EFDC68B4D778F7B390C /* Copy Pods Resources */ = { 280 | isa = PBXShellScriptBuildPhase; 281 | buildActionMask = 2147483647; 282 | files = ( 283 | ); 284 | inputPaths = ( 285 | ); 286 | name = "Copy Pods Resources"; 287 | outputPaths = ( 288 | ); 289 | runOnlyForDeploymentPostprocessing = 0; 290 | shellPath = /bin/sh; 291 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; 292 | showEnvVarsInLog = 0; 293 | }; 294 | 4705BE80F69E43FFBD0BE466 /* Check Pods Manifest.lock */ = { 295 | isa = PBXShellScriptBuildPhase; 296 | buildActionMask = 2147483647; 297 | files = ( 298 | ); 299 | inputPaths = ( 300 | ); 301 | name = "Check Pods Manifest.lock"; 302 | outputPaths = ( 303 | ); 304 | runOnlyForDeploymentPostprocessing = 0; 305 | shellPath = /bin/sh; 306 | shellScript = "if [[ -z \"${PODS_ROOT}\" ]] ; then\n PODS_ROOT=\"./Pods\"\nfi\ndiff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 307 | }; 308 | D9D6816F15AB4AA2A4FC8954 /* Check Pods Manifest.lock */ = { 309 | isa = PBXShellScriptBuildPhase; 310 | buildActionMask = 2147483647; 311 | files = ( 312 | ); 313 | inputPaths = ( 314 | ); 315 | name = "Check Pods Manifest.lock"; 316 | outputPaths = ( 317 | ); 318 | runOnlyForDeploymentPostprocessing = 0; 319 | shellPath = /bin/sh; 320 | shellScript = "if [[ -z \"${PODS_ROOT}\" ]] ; then\n PODS_ROOT=\"./Pods\"\nfi\ndiff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; 321 | showEnvVarsInLog = 0; 322 | }; 323 | EA350182CD3A49308F4218CA /* Copy Pods Resources */ = { 324 | isa = PBXShellScriptBuildPhase; 325 | buildActionMask = 2147483647; 326 | files = ( 327 | ); 328 | inputPaths = ( 329 | ); 330 | name = "Copy Pods Resources"; 331 | outputPaths = ( 332 | ); 333 | runOnlyForDeploymentPostprocessing = 0; 334 | shellPath = /bin/sh; 335 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; 336 | showEnvVarsInLog = 0; 337 | }; 338 | /* End PBXShellScriptBuildPhase section */ 339 | 340 | /* Begin PBXSourcesBuildPhase section */ 341 | 590677C518E4E38B00D2B893 /* Sources */ = { 342 | isa = PBXSourcesBuildPhase; 343 | buildActionMask = 2147483647; 344 | files = ( 345 | 5909919919EFB7FA003DA269 /* ASAPIClient+Network.m in Sources */, 346 | 590677D218E4E38B00D2B893 /* test.m in Sources */, 347 | ); 348 | runOnlyForDeploymentPostprocessing = 0; 349 | }; 350 | 591C932F18E265C3001F1A0F /* Sources */ = { 351 | isa = PBXSourcesBuildPhase; 352 | buildActionMask = 2147483647; 353 | files = ( 354 | 5D7B33401B4BBD7B00F12D56 /* ASExpiringCache.m in Sources */, 355 | 5D7B33431B4BBDEB00F12D56 /* ASExpiringCacheItem.m in Sources */, 356 | 591C936718E267B5001F1A0F /* ASQuery.m in Sources */, 357 | 591C936518E267B5001F1A0F /* ASAPIClient+Network.m in Sources */, 358 | 591C936818E267B5001F1A0F /* ASRemoteIndex.m in Sources */, 359 | 591C936618E267B5001F1A0F /* ASAPIClient.m in Sources */, 360 | 5D85ED221B28659A001C1C5B /* ASBrowseIterator.m in Sources */, 361 | ); 362 | runOnlyForDeploymentPostprocessing = 0; 363 | }; 364 | /* End PBXSourcesBuildPhase section */ 365 | 366 | /* Begin PBXTargetDependency section */ 367 | 590677D518E4E38C00D2B893 /* PBXTargetDependency */ = { 368 | isa = PBXTargetDependency; 369 | target = 591C933218E265C3001F1A0F /* algoliasearch-client-objc */; 370 | targetProxy = 590677D418E4E38C00D2B893 /* PBXContainerItemProxy */; 371 | }; 372 | /* End PBXTargetDependency section */ 373 | 374 | /* Begin PBXVariantGroup section */ 375 | 590677CE18E4E38B00D2B893 /* InfoPlist.strings */ = { 376 | isa = PBXVariantGroup; 377 | children = ( 378 | 590677CF18E4E38B00D2B893 /* en */, 379 | ); 380 | name = InfoPlist.strings; 381 | sourceTree = ""; 382 | }; 383 | /* End PBXVariantGroup section */ 384 | 385 | /* Begin XCBuildConfiguration section */ 386 | 590677D718E4E38C00D2B893 /* Debug */ = { 387 | isa = XCBuildConfiguration; 388 | buildSettings = { 389 | COMBINE_HIDPI_IMAGES = YES; 390 | FRAMEWORK_SEARCH_PATHS = ( 391 | "$(DEVELOPER_FRAMEWORKS_DIR)", 392 | "$(inherited)", 393 | ); 394 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 395 | GCC_PRECOMPILE_PREFIX_HEADER = NO; 396 | GCC_PREFIX_HEADER = ""; 397 | GCC_PREPROCESSOR_DEFINITIONS = ( 398 | "COCOAPODS=1", 399 | "$(inherited)", 400 | ); 401 | HEADER_SEARCH_PATHS = ( 402 | "$(inherited)", 403 | "\"${PODS_ROOT}/Headers/Public/AFNetworking\"", 404 | "\"${PODS_ROOT}/Headers/Public\"", 405 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 406 | ); 407 | INFOPLIST_FILE = "test/test-Info.plist"; 408 | LIBRARY_SEARCH_PATHS = ( 409 | "$(inherited)", 410 | "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/algoliasearch-client-objc-ezaqtrvmayymwwavbcfvoeuiphpx/Build/Products/Debug", 411 | ); 412 | LINK_WITH_STANDARD_LIBRARIES = YES; 413 | MACOSX_DEPLOYMENT_TARGET = 10.9; 414 | PODS_ROOT = "${SRCROOT}/Pods"; 415 | PRODUCT_NAME = "$(TARGET_NAME)"; 416 | WRAPPER_EXTENSION = xctest; 417 | }; 418 | name = Debug; 419 | }; 420 | 590677D818E4E38C00D2B893 /* Release */ = { 421 | isa = XCBuildConfiguration; 422 | buildSettings = { 423 | COMBINE_HIDPI_IMAGES = YES; 424 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 425 | FRAMEWORK_SEARCH_PATHS = ( 426 | "$(DEVELOPER_FRAMEWORKS_DIR)", 427 | "$(inherited)", 428 | ); 429 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 430 | GCC_PRECOMPILE_PREFIX_HEADER = NO; 431 | GCC_PREFIX_HEADER = ""; 432 | GCC_PREPROCESSOR_DEFINITIONS = "COCOAPODS=1"; 433 | HEADER_SEARCH_PATHS = ( 434 | "$(inherited)", 435 | "\"${PODS_ROOT}/Headers/Public/AFNetworking\"", 436 | "\"${PODS_ROOT}/Headers/Public\"", 437 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 438 | ); 439 | INFOPLIST_FILE = "test/test-Info.plist"; 440 | LIBRARY_SEARCH_PATHS = ( 441 | "$(inherited)", 442 | "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/algoliasearch-client-objc-ezaqtrvmayymwwavbcfvoeuiphpx/Build/Products/Debug", 443 | ); 444 | LINK_WITH_STANDARD_LIBRARIES = YES; 445 | MACOSX_DEPLOYMENT_TARGET = 10.9; 446 | PODS_ROOT = "${SRCROOT}/Pods"; 447 | PRODUCT_NAME = "$(TARGET_NAME)"; 448 | WRAPPER_EXTENSION = xctest; 449 | }; 450 | name = Release; 451 | }; 452 | 591C935418E265C3001F1A0F /* Debug */ = { 453 | isa = XCBuildConfiguration; 454 | buildSettings = { 455 | ALWAYS_SEARCH_USER_PATHS = NO; 456 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 457 | CLANG_CXX_LIBRARY = "libc++"; 458 | CLANG_ENABLE_MODULES = YES; 459 | CLANG_ENABLE_OBJC_ARC = YES; 460 | CLANG_WARN_BOOL_CONVERSION = YES; 461 | CLANG_WARN_CONSTANT_CONVERSION = YES; 462 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 463 | CLANG_WARN_EMPTY_BODY = YES; 464 | CLANG_WARN_ENUM_CONVERSION = YES; 465 | CLANG_WARN_INT_CONVERSION = YES; 466 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 467 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 468 | COPY_PHASE_STRIP = NO; 469 | GCC_C_LANGUAGE_STANDARD = gnu99; 470 | GCC_DYNAMIC_NO_PIC = NO; 471 | GCC_OPTIMIZATION_LEVEL = 0; 472 | GCC_PREPROCESSOR_DEFINITIONS = ( 473 | "DEBUG=1", 474 | "$(inherited)", 475 | ); 476 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 477 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 478 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 479 | GCC_WARN_UNDECLARED_SELECTOR = YES; 480 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 481 | GCC_WARN_UNUSED_FUNCTION = YES; 482 | GCC_WARN_UNUSED_VARIABLE = YES; 483 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 484 | ONLY_ACTIVE_ARCH = YES; 485 | SDKROOT = macosx; 486 | }; 487 | name = Debug; 488 | }; 489 | 591C935518E265C3001F1A0F /* Release */ = { 490 | isa = XCBuildConfiguration; 491 | buildSettings = { 492 | ALWAYS_SEARCH_USER_PATHS = NO; 493 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 494 | CLANG_CXX_LIBRARY = "libc++"; 495 | CLANG_ENABLE_MODULES = YES; 496 | CLANG_ENABLE_OBJC_ARC = YES; 497 | CLANG_WARN_BOOL_CONVERSION = YES; 498 | CLANG_WARN_CONSTANT_CONVERSION = YES; 499 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 500 | CLANG_WARN_EMPTY_BODY = YES; 501 | CLANG_WARN_ENUM_CONVERSION = YES; 502 | CLANG_WARN_INT_CONVERSION = YES; 503 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 504 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 505 | COPY_PHASE_STRIP = YES; 506 | ENABLE_NS_ASSERTIONS = NO; 507 | GCC_C_LANGUAGE_STANDARD = gnu99; 508 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 509 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 510 | GCC_WARN_UNDECLARED_SELECTOR = YES; 511 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 512 | GCC_WARN_UNUSED_FUNCTION = YES; 513 | GCC_WARN_UNUSED_VARIABLE = YES; 514 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 515 | SDKROOT = macosx; 516 | VALIDATE_PRODUCT = YES; 517 | }; 518 | name = Release; 519 | }; 520 | 591C935718E265C3001F1A0F /* Debug */ = { 521 | isa = XCBuildConfiguration; 522 | baseConfigurationReference = EE723D9FA715B3A80A9DBE58 /* Pods.debug.xcconfig */; 523 | buildSettings = { 524 | COMBINE_HIDPI_IMAGES = YES; 525 | DSTROOT = /tmp/algoliasearch_client_objc.dst; 526 | FRAMEWORK_SEARCH_PATHS = ( 527 | "$(inherited)", 528 | "$(DEVELOPER_FRAMEWORKS_DIR)", 529 | ); 530 | GCC_PRECOMPILE_PREFIX_HEADER = NO; 531 | GCC_PREFIX_HEADER = ""; 532 | LIBRARY_SEARCH_PATHS = ( 533 | "$(inherited)", 534 | "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/algoliasearch-client-objc-ezaqtrvmayymwwavbcfvoeuiphpx/Build/Products/Debug", 535 | ); 536 | OTHER_LDFLAGS = ( 537 | "$(inherited)", 538 | "-ObjC", 539 | ); 540 | PRODUCT_NAME = "$(TARGET_NAME)"; 541 | SKIP_INSTALL = YES; 542 | STRIP_INSTALLED_PRODUCT = YES; 543 | }; 544 | name = Debug; 545 | }; 546 | 591C935818E265C3001F1A0F /* Release */ = { 547 | isa = XCBuildConfiguration; 548 | baseConfigurationReference = 93A3C6D5C4BEC322D8180EA7 /* Pods.release.xcconfig */; 549 | buildSettings = { 550 | COMBINE_HIDPI_IMAGES = YES; 551 | DSTROOT = /tmp/algoliasearch_client_objc.dst; 552 | FRAMEWORK_SEARCH_PATHS = ( 553 | "$(inherited)", 554 | "$(DEVELOPER_FRAMEWORKS_DIR)", 555 | ); 556 | GCC_PRECOMPILE_PREFIX_HEADER = NO; 557 | GCC_PREFIX_HEADER = ""; 558 | LIBRARY_SEARCH_PATHS = ( 559 | "$(inherited)", 560 | "$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/algoliasearch-client-objc-ezaqtrvmayymwwavbcfvoeuiphpx/Build/Products/Debug", 561 | ); 562 | OTHER_LDFLAGS = ( 563 | "$(inherited)", 564 | "-ObjC", 565 | ); 566 | PRODUCT_NAME = "$(TARGET_NAME)"; 567 | SKIP_INSTALL = YES; 568 | STRIP_INSTALLED_PRODUCT = YES; 569 | }; 570 | name = Release; 571 | }; 572 | /* End XCBuildConfiguration section */ 573 | 574 | /* Begin XCConfigurationList section */ 575 | 590677D618E4E38C00D2B893 /* Build configuration list for PBXNativeTarget "test" */ = { 576 | isa = XCConfigurationList; 577 | buildConfigurations = ( 578 | 590677D718E4E38C00D2B893 /* Debug */, 579 | 590677D818E4E38C00D2B893 /* Release */, 580 | ); 581 | defaultConfigurationIsVisible = 0; 582 | defaultConfigurationName = Release; 583 | }; 584 | 591C932E18E265C3001F1A0F /* Build configuration list for PBXProject "algoliasearch-client-objc" */ = { 585 | isa = XCConfigurationList; 586 | buildConfigurations = ( 587 | 591C935418E265C3001F1A0F /* Debug */, 588 | 591C935518E265C3001F1A0F /* Release */, 589 | ); 590 | defaultConfigurationIsVisible = 0; 591 | defaultConfigurationName = Release; 592 | }; 593 | 591C935618E265C3001F1A0F /* Build configuration list for PBXNativeTarget "algoliasearch-client-objc" */ = { 594 | isa = XCConfigurationList; 595 | buildConfigurations = ( 596 | 591C935718E265C3001F1A0F /* Debug */, 597 | 591C935818E265C3001F1A0F /* Release */, 598 | ); 599 | defaultConfigurationIsVisible = 0; 600 | defaultConfigurationName = Release; 601 | }; 602 | /* End XCConfigurationList section */ 603 | }; 604 | rootObject = 591C932B18E265C3001F1A0F /* Project object */; 605 | } 606 | -------------------------------------------------------------------------------- /algoliasearch-client-objc.xcodeproj/xcshareddata/xcschemes/travis-test.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 55 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 74 | 76 | 77 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /algoliasearch-client-objc.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /algoliasearch-client-objc.xcworkspace/xcshareddata/algoliasearch-client-objc.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 4BF47B36-440D-4BA5-A97A-925BCD9A113B 9 | IDESourceControlProjectName 10 | algoliasearch-client-objc 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 95CE8D3CD2EE20AACCB7738888F7D91EE95C3393 14 | https://github.com/algolia/algoliasearch-client-objc.git 15 | 16 | IDESourceControlProjectPath 17 | algoliasearch-client-objc.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 95CE8D3CD2EE20AACCB7738888F7D91EE95C3393 21 | .. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/algolia/algoliasearch-client-objc.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | 95CE8D3CD2EE20AACCB7738888F7D91EE95C3393 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 95CE8D3CD2EE20AACCB7738888F7D91EE95C3393 36 | IDESourceControlWCCName 37 | algoliasearch-client-objc 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/ASAPIClient+Network.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2013 Algolia 3 | // http://www.algolia.com/ 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 13 | // all 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 21 | // THE SOFTWARE. 22 | // 23 | 24 | #import 25 | #import "ASAPIClient.h" 26 | 27 | @interface ASAPIClient (Network) 28 | 29 | /** 30 | * Return URL encoded version of str 31 | */ 32 | +(NSString *) urlEncode:(NSString*)str; 33 | 34 | /** 35 | * Perform an HTTP query 36 | */ 37 | -(AFHTTPRequestOperation *) performHTTPQuery:(NSString*)path method:(NSString*)method body:(NSDictionary*)body managers:(NSArray*)managers index:(NSUInteger)index timeout:(NSTimeInterval)timeout 38 | success:(void(^)(id JSON))success failure:(void(^)(NSString *errorMessage))failure; 39 | 40 | -(void) cancelQueries:(NSString*)method path:(NSString*)path; 41 | 42 | @end -------------------------------------------------------------------------------- /src/ASAPIClient+Network.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2013 Algolia 3 | // http://www.algolia.com/ 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 13 | // all 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 21 | // THE SOFTWARE. 22 | // 23 | 24 | #import "ASAPIClient+Network.h" 25 | 26 | @implementation ASAPIClient (Network) 27 | 28 | +(NSString *) urlEncode:(NSString*)originalStr { 29 | return (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)originalStr, NULL, (CFStringRef)@"!*'();:@&=+$,/?%#[]", kCFStringEncodingUTF8 )); 30 | } 31 | 32 | -(void) cancelQueries:(NSString*)method path:(NSString*)path 33 | { 34 | NSUInteger count = [self.searchOperationManagers count]; 35 | for (NSUInteger i = 0; i < count; ++i) { 36 | AFHTTPRequestOperationManager *httpRequestOperationManager = (self.searchOperationManagers)[i]; 37 | for (AFHTTPRequestOperation *operation in httpRequestOperationManager.operationQueue.operations) { 38 | if ([operation.request.URL.path isEqualToString:path]) { 39 | if ([operation.request.HTTPMethod isEqualToString:method]) { 40 | [operation cancel]; 41 | } 42 | } 43 | } 44 | } 45 | count = [self.writeOperationManagers count]; 46 | for (NSUInteger i = 0; i < count; ++i) { 47 | AFHTTPRequestOperationManager *httpRequestOperationManager = (self.writeOperationManagers)[i]; 48 | for (AFHTTPRequestOperation *operation in httpRequestOperationManager.operationQueue.operations) { 49 | if ([operation.request.URL.path isEqualToString:path]) { 50 | if ([operation.request.HTTPMethod isEqualToString:method]) { 51 | [operation cancel]; 52 | } 53 | } 54 | } 55 | } 56 | } 57 | 58 | -(AFHTTPRequestOperation *) performHTTPQuery: (NSString*)path method:(NSString*)method body:(NSDictionary*)body managers:(NSArray*)managers index:(NSUInteger)index timeout:(NSTimeInterval)timeout 59 | success:(void(^)(id JSON))success failure:(void(^)(NSString *errorMessage))failure 60 | { 61 | assert(index < [managers count]); 62 | AFHTTPRequestOperationManager *httpRequestOperationManager = (managers)[index]; 63 | NSMutableURLRequest *request = [httpRequestOperationManager.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:path relativeToURL:httpRequestOperationManager.baseURL] absoluteString] parameters:body error:nil]; 64 | [httpRequestOperationManager.requestSerializer setTimeoutInterval:timeout]; 65 | 66 | AFHTTPRequestOperation *operation = [httpRequestOperationManager HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id JSON) { 67 | if ((operation.response.statusCode / 100) == 2) { 68 | success(JSON); 69 | } else { 70 | failure(@"No error message"); 71 | } 72 | } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 73 | if ((operation.response.statusCode / 100) == 4) { 74 | NSData *errorData = error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey]; 75 | NSDictionary *JSON = nil; 76 | if (errorData != nil) { 77 | JSON = [NSJSONSerialization JSONObjectWithData: errorData options:kNilOptions error:nil]; 78 | failure(JSON[@"message"]); 79 | } else { 80 | failure(error.localizedDescription); 81 | } 82 | 83 | } else { 84 | if ((index + 1) < [managers count]) { 85 | [self performHTTPQuery:path method:method body:body managers:managers index:(index + 1) timeout:(timeout + 10) success:success failure:failure]; 86 | } else { 87 | failure(error.description); 88 | } 89 | } 90 | }]; 91 | 92 | if (!self.startOperationsManually) { 93 | [httpRequestOperationManager.operationQueue addOperation:operation]; 94 | } 95 | 96 | return operation; 97 | } 98 | 99 | @end 100 | -------------------------------------------------------------------------------- /src/ASAPIClient.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2013 Algolia 3 | // http://www.algolia.com/ 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 13 | // all 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 21 | // THE SOFTWARE. 22 | // 23 | 24 | #import 25 | #import 26 | #import "ASRemoteIndex.h" 27 | 28 | FOUNDATION_EXPORT NSString *const Version; 29 | 30 | /** 31 | * Entry point in the Objective-C API. 32 | * You should instantiate a Client object with your ApplicationID, ApiKey and Hosts 33 | * to start using Algolia Search API 34 | */ 35 | @interface ASAPIClient : NSObject 36 | 37 | /** 38 | * Algolia Search initialization 39 | * 40 | * @param applicationID the application ID you have in your admin interface 41 | * @param apiKey a valid API key for the service 42 | */ 43 | +(instancetype) apiClientWithApplicationID:(NSString*)applicationID apiKey:(NSString*)apiKey; 44 | 45 | /** 46 | * Algolia Search initialization 47 | * 48 | * @param applicationID the application ID you have in your admin interface 49 | * @param apiKey a valid API key for the service 50 | * @param hostnames the list of hosts that you have received for the service 51 | */ 52 | +(instancetype) apiClientWithApplicationID:(NSString*)applicationID apiKey:(NSString*)apiKey hostnames:(NSArray*)hostnames; 53 | 54 | /** 55 | * Algolia Search initialization 56 | * 57 | * @param applicationID the application ID you have in your admin interface 58 | * @param apiKey a valid API key for the service 59 | * @param hostnames the list of hosts that you have received for the service 60 | * @param dsn set to true if your account has the Distributed Search Option 61 | * @param dsnHost override the automatic computation of dsn hostname 62 | * @param tagFilters value of the header X-Algolia-TagFilters 63 | * @param userToken value of the header X-Algolia-UserToken 64 | */ 65 | -(instancetype) initWithApplicationID:(NSString*)papplicationID apiKey:(NSString*)papiKey hostnames:(NSArray*)phostnames tagFilters:(NSString*)tagFiltersHeader userToken:(NSString*)userTokenHeader; 66 | 67 | /** 68 | * List all existing indexes 69 | * return an JSON Object in the success block in the form: 70 | * { "items": [ {"name": "contacts", "createdAt": "2013-01-18T15:33:13.556Z"}, 71 | * {"name": "notes", "createdAt": "2013-01-18T15:33:13.556Z"}]} 72 | */ 73 | -(AFHTTPRequestOperation *) listIndexes:(void(^)(ASAPIClient *client, NSDictionary *result))success 74 | failure:(void(^)(ASAPIClient *client, NSString *errorMessage))failure; 75 | 76 | /** 77 | * Delete an index 78 | * 79 | * @param indexName the name of index to delete 80 | * return an object containing a "deletedAt" attribute in the success block 81 | */ 82 | -(AFHTTPRequestOperation *) deleteIndex:(NSString*)indexName 83 | success:(void(^)(ASAPIClient *client, NSString *indexName, NSDictionary *result))success 84 | failure:(void(^)(ASAPIClient *client, NSString *indexName, NSString *errorMessage))failure; 85 | 86 | /** 87 | * Move an existing index. 88 | * 89 | * @param srcIndexName the name of index to copy. 90 | * @param dstIndexName the new index name that will contains srcIndexName (destination will be overriten if it already exist). 91 | */ 92 | -(AFHTTPRequestOperation *) moveIndex:(NSString*)srcIndexName 93 | to:(NSString*)dstIndexName 94 | success:(void(^)(ASAPIClient *client, NSString *srcIndexName, NSString *dstIndexName, NSDictionary *result))success 95 | failure:(void(^)(ASAPIClient *client, NSString *srcIndexName, NSString *dstIndexName, NSString *errorMessage))failure; 96 | /** 97 | * Copy an existing index. 98 | * 99 | * @param srcIndexName the name of index to copy. 100 | * @param dstIndexName the new index name that will contains a copy of srcIndexName (destination will be overriten if it already exist). 101 | */ 102 | -(AFHTTPRequestOperation *) copyIndex:(NSString*)srcIndexName 103 | to:(NSString*)dstIndexName 104 | success:(void(^)(ASAPIClient *client, NSString *srcIndexName, NSString *dstIndexName, NSDictionary *result))success 105 | failure:(void(^)(ASAPIClient *client, NSString *srcIndexName, NSString *dstIndexName, NSString *errorMessage))failure; 106 | 107 | /** 108 | * Return 10 last log entries. 109 | */ 110 | -(AFHTTPRequestOperation *) getLogs:(void(^)(ASAPIClient *client, NSDictionary *result))success 111 | failure:(void(^)(ASAPIClient *client, NSString *errorMessage))failure; 112 | 113 | /** 114 | * Return last logs entries. 115 | * 116 | * @param offset Specify the first entry to retrieve (0-based, 0 is the most recent log entry). 117 | * @param length Specify the maximum number of entries to retrieve starting at offset. Maximum allowed value: 1000. 118 | */ 119 | -(AFHTTPRequestOperation *) getLogsWithOffset:(NSUInteger)offset 120 | length:(NSUInteger)length 121 | success:(void(^)(ASAPIClient *client, NSUInteger offset, NSUInteger length, NSDictionary *result))success 122 | failure:(void(^)(ASAPIClient *client, NSUInteger offset, NSUInteger length, NSString *errorMessage))failure; 123 | 124 | /** 125 | * Return last logs entries. 126 | * 127 | * @param offset Specify the first entry to retrieve (0-based, 0 is the most recent log entry). 128 | * @param length Specify the maximum number of entries to retrieve starting at offset. Maximum allowed value: 1000. 129 | */ 130 | -(AFHTTPRequestOperation *) getLogsWithType:(NSUInteger)offset 131 | length:(NSUInteger)length 132 | type:(NSString*)type 133 | success:(void(^)(ASAPIClient *client, NSUInteger offset, NSUInteger length, NSString* type, NSDictionary *result))success 134 | failure:(void(^)(ASAPIClient *client, NSUInteger offset, NSUInteger length, NSString* type, NSString *errorMessage))failure; 135 | 136 | /** 137 | * Get the index object initialized (no server call needed for initialization) 138 | * 139 | * @param indexName the name of index 140 | */ 141 | -(ASRemoteIndex*) getIndex:(NSString*)indexName; 142 | 143 | /** 144 | * Allow to set custom extra header 145 | * 146 | * @param value of the header 147 | * @param key of the header 148 | */ 149 | -(void) setExtraHeader:(NSString*)value forHeaderField:key; 150 | 151 | /** 152 | * Query multiple indexes with one API call 153 | * 154 | * @param query contains an array of queries with the associated index (NSArray of NSDictionary object @{"indexName":@"targettedIndex", @"query": theASQueryObject }). 155 | */ 156 | -(AFHTTPRequestOperation *) multipleQueries:(NSArray*)query 157 | success:(void(^)(ASAPIClient *client, NSArray *queries, NSDictionary *result))success 158 | failure: (void(^)(ASAPIClient *client, NSArray *queries, NSString *errorMessage))failure; 159 | 160 | /** 161 | * Query multiple indexes with one API call 162 | * 163 | * @param query contains an array of queries with the associated index (NSArray of NSDictionary object @{"indexName":@"targettedIndex", @"query": theASQueryObject }). 164 | * @param strategy name of the strategy applied to the sequence of queries default:none 165 | */ 166 | -(AFHTTPRequestOperation *) multipleQueries:(NSArray*)query 167 | withStrategy:(NSString*)strategy 168 | success:(void(^)(ASAPIClient *client, NSArray *queries, NSString* strategy, NSDictionary *result))success 169 | failure: (void(^)(ASAPIClient *client, NSArray *queries, NSString* strategy, NSString *errorMessage))failure; 170 | 171 | /** 172 | * List all existing user keys with their associated ACLs 173 | */ 174 | -(AFHTTPRequestOperation *) listUserKeys:(void(^)(ASAPIClient *client, NSDictionary *result))success 175 | failure:(void(^)(ASAPIClient *client, NSString *errorMessage))failure; 176 | 177 | /** 178 | * Get ACL of a user key 179 | */ 180 | -(AFHTTPRequestOperation *) getUserKeyACL:(NSString*)key 181 | success:(void(^)(ASAPIClient *client, NSString *key, NSDictionary *result))success 182 | failure:(void(^)(ASAPIClient *client, NSString *key, NSString *errorMessage))failure; 183 | 184 | /** 185 | * Delete an existing user key 186 | */ 187 | -(AFHTTPRequestOperation *) deleteUserKey:(NSString*)key 188 | success:(void(^)(ASAPIClient *client, NSString *key, NSDictionary *result))success 189 | failure:(void(^)(ASAPIClient *client, NSString *key, NSString *errorMessage))failure; 190 | 191 | /** 192 | * Create a new user key 193 | * 194 | * @param acls the list of ACL for this key. Defined by an array of NSString that 195 | * can contains the following values: 196 | * - search: allow to search (https and http) 197 | * - addObject: allows to add/update an object in the index (https only) 198 | * - deleteObject : allows to delete an existing object (https only) 199 | * - deleteIndex : allows to delete index content (https only) 200 | * - settings : allows to get index settings (https only) 201 | * - editSettings : allows to change index settings (https only) 202 | */ 203 | -(AFHTTPRequestOperation *) addUserKey:(NSArray*)acls 204 | success:(void(^)(ASAPIClient *client, NSArray* acls, NSDictionary *result))success 205 | failure:(void(^)(ASAPIClient *client, NSArray* acls, NSString *errorMessage))failure; 206 | 207 | /** 208 | * Create a new user key 209 | * 210 | * @param acls the list of ACL for this key. Defined by an array of NSString that 211 | * can contains the following values: 212 | * - search: allow to search (https and http) 213 | * - addObject: allows to add/update an object in the index (https only) 214 | * - deleteObject : allows to delete an existing object (https only) 215 | * - deleteIndex : allows to delete index content (https only) 216 | * - settings : allows to get index settings (https only) 217 | * - editSettings : allows to change index settings (https only) 218 | * @param params The list of parameters for this key. Defined by a NSDictionary that 219 | * can contains the following values: 220 | * - acl: array of string 221 | * - indices: array of string 222 | * - validity: int 223 | * - referers: array of string 224 | * - description: string 225 | * - maxHitsPerQuery: integer 226 | * - queryParameters: string 227 | * - maxQueriesPerIPPerHour: integer 228 | */ 229 | -(AFHTTPRequestOperation *) addUserKey:(NSArray*)acls 230 | withParams:(NSDictionary*)params 231 | success:(void(^)(ASAPIClient *client, NSArray* acls, NSDictionary* params, NSDictionary *result))success 232 | failure:(void(^)(ASAPIClient *client, NSArray* acls, NSDictionary* params, NSString *errorMessage))failure; 233 | 234 | /** 235 | * Create a new user key 236 | * 237 | * @param acls the list of ACL for this key. Defined by an array of NSString that 238 | * can contains the following values: 239 | * - search: allow to search (https and http) 240 | * - addObject: allows to add/update an object in the index (https only) 241 | * - deleteObject : allows to delete an existing object (https only) 242 | * - deleteIndex : allows to delete index content (https only) 243 | * - settings : allows to get index settings (https only) 244 | * - editSettings : allows to change index settings (https only) 245 | * @param validity the number of seconds after which the key will be automatically removed (0 means no time limit for this key) 246 | * @param maxQueriesPerIPPerHour Specify the maximum number of API calls allowed from an IP address per hour. Defaults to 0 (no rate limit). 247 | * @param maxHitsPerQuery Specify the maximum number of hits this API key can retrieve in one call. Defaults to 0 (unlimited) 248 | */ 249 | -(AFHTTPRequestOperation *) addUserKey:(NSArray*)acls 250 | withValidity:(NSUInteger)validity 251 | maxQueriesPerIPPerHour:(NSUInteger)maxQueriesPerIPPerHour 252 | maxHitsPerQuery:(NSUInteger)maxHitsPerQuery 253 | success:(void(^)(ASAPIClient *client, NSArray *acls, NSDictionary *result))success 254 | failure:(void(^)(ASAPIClient *client, NSArray *acls, NSString *errorMessage))failure; 255 | 256 | /** 257 | * Create a new user key 258 | * 259 | * @param acls the list of ACL for this key. Defined by an array of NSString that 260 | * can contains the following values: 261 | * - search: allow to search (https and http) 262 | * - addObject: allows to add/update an object in the index (https only) 263 | * - deleteObject : allows to delete an existing object (https only) 264 | * - deleteIndex : allows to delete index content (https only) 265 | * - settings : allows to get index settings (https only) 266 | * - editSettings : allows to change index settings (https only) 267 | * @param indexes restrict this new API key to specific index names 268 | * @param validity the number of seconds after which the key will be automatically removed (0 means no time limit for this key) 269 | * @param maxQueriesPerIPPerHour Specify the maximum number of API calls allowed from an IP address per hour. Defaults to 0 (no rate limit). 270 | * @param maxHitsPerQuery Specify the maximum number of hits this API key can retrieve in one call. Defaults to 0 (unlimited) 271 | */ 272 | -(AFHTTPRequestOperation *) addUserKey:(NSArray*)acls 273 | withIndexes:(NSArray*)indexes 274 | withValidity:(NSUInteger)validity 275 | maxQueriesPerIPPerHour:(NSUInteger)maxQueriesPerIPPerHour 276 | maxHitsPerQuery:(NSUInteger)maxHitsPerQuery 277 | success:(void(^)(ASAPIClient *client, NSArray *acls, NSArray *indexes, NSDictionary *result))success 278 | failure:(void(^)(ASAPIClient *client, NSArray *acls, NSArray *indexes, NSString *errorMessage))failure; 279 | 280 | /** 281 | * Update a user key 282 | * 283 | * @params params the list of parameters for this key. Defined by a NSDictionary that 284 | * can contains the following values: 285 | * - acl: array of string 286 | * - indices: array of string 287 | * - validity: int 288 | * - referers: array of string 289 | * - description: string 290 | * - maxHitsPerQuery: integer 291 | * - queryParameters: string 292 | * - maxQueriesPerIPPerHour: integer 293 | */ 294 | -(AFHTTPRequestOperation *) updateUserKey:(NSString*)key 295 | withParams:(NSDictionary*)params 296 | success:(void(^)(ASAPIClient *client, NSString *key, NSDictionary *params, NSDictionary *result))success 297 | failure:(void(^)(ASAPIClient *client, NSString *key, NSDictionary *params, NSString *errorMessage))failure; 298 | 299 | /** 300 | * Update a user key 301 | * 302 | * @param acls the list of ACL for this key. Defined by an array of NSString that 303 | * can contains the following values: 304 | * - search: allow to search (https and http) 305 | * - addObject: allows to add/update an object in the index (https only) 306 | * - deleteObject : allows to delete an existing object (https only) 307 | * - deleteIndex : allows to delete index content (https only) 308 | * - settings : allows to get index settings (https only) 309 | * - editSettings : allows to change index settings (https only) 310 | */ 311 | -(AFHTTPRequestOperation *) updateUserKey:(NSString*)key 312 | withACL:(NSArray*)acls 313 | success:(void(^)(ASAPIClient *clients, NSString *key, NSArray *acls, NSDictionary *result))success 314 | failure:(void(^)(ASAPIClient *client, NSString *key, NSArray *acls, NSString *errorMessage))failure; 315 | 316 | /** 317 | * Update a user key 318 | * 319 | * @param acls the list of ACL for this key. Defined by an array of NSString that 320 | * can contains the following values: 321 | * - search: allow to search (https and http) 322 | * - addObject: allows to add/update an object in the index (https only) 323 | * - deleteObject : allows to delete an existing object (https only) 324 | * - deleteIndex : allows to delete index content (https only) 325 | * - settings : allows to get index settings (https only) 326 | * - editSettings : allows to change index settings (https only) 327 | * @param validity the number of seconds after which the key will be automatically removed (0 means no time limit for this key) 328 | * @param maxQueriesPerIPPerHour Specify the maximum number of API calls allowed from an IP address per hour. Defaults to 0 (no rate limit). 329 | * @param maxHitsPerQuery Specify the maximum number of hits this API key can retrieve in one call. Defaults to 0 (unlimited) 330 | */ 331 | -(AFHTTPRequestOperation *) updateUserKey:(NSString*)key 332 | withACL:(NSArray*)acls 333 | withValidity:(NSUInteger)validity 334 | maxQueriesPerIPPerHour:(NSUInteger)maxQueriesPerIPPerHour 335 | maxHitsPerQuery:(NSUInteger)maxHitsPerQuery 336 | success:(void(^)(ASAPIClient *client, NSString *key, NSArray *acls, NSDictionary *result))success 337 | failure:(void(^)(ASAPIClient *client, NSString *key, NSArray *acls, NSString *errorMessage))failure; 338 | 339 | /** 340 | * Update a user key 341 | * 342 | * @param acls the list of ACL for this key. Defined by an array of NSString that 343 | * can contains the following values: 344 | * - search: allow to search (https and http) 345 | * - addObject: allows to add/update an object in the index (https only) 346 | * - deleteObject : allows to delete an existing object (https only) 347 | * - deleteIndex : allows to delete index content (https only) 348 | * - settings : allows to get index settings (https only) 349 | * - editSettings : allows to change index settings (https only) 350 | * @param indexes restrict this new API key to specific index names 351 | * @param validity the number of seconds after which the key will be automatically removed (0 means no time limit for this key) 352 | * @param maxQueriesPerIPPerHour Specify the maximum number of API calls allowed from an IP address per hour. Defaults to 0 (no rate limit). 353 | * @param maxHitsPerQuery Specify the maximum number of hits this API key can retrieve in one call. Defaults to 0 (unlimited) 354 | */ 355 | -(AFHTTPRequestOperation *) updateUserKey:(NSString*)key 356 | withACL:(NSArray*)acls withIndexes:(NSArray*)indexes 357 | withValidity:(NSUInteger)validity 358 | maxQueriesPerIPPerHour:(NSUInteger)maxQueriesPerIPPerHour 359 | maxHitsPerQuery:(NSUInteger)maxHitsPerQuery 360 | success:(void(^)(ASAPIClient *client, NSString *key, NSArray *acls, NSArray *indexes, NSDictionary *result))success 361 | failure:(void(^)(ASAPIClient *client, NSString *key, NSArray *acls, NSArray *indexes, NSString *errorMessage))failure; 362 | 363 | /** 364 | * Send custom batch targeting multiple indexes 365 | * 366 | * @param requests contains an array of objects (NSArray of NSDictionary object). 367 | */ 368 | -(AFHTTPRequestOperation *) batch:(NSArray*)requests 369 | success:(void(^)(ASAPIClient *client, NSDictionary *requests, NSDictionary *result))success 370 | failure:(void(^)(ASAPIClient *client, NSDictionary *requests, NSString *errorMessage))failure; 371 | 372 | @property (readonly, nonatomic) NSString *applicationID; 373 | @property (readonly, nonatomic) NSString *apiKey; 374 | @property (readonly, nonatomic) NSArray *writeHostnames; 375 | @property (readonly, nonatomic) NSArray *searchHostnames; 376 | @property (readonly, nonatomic) NSArray *searchOperationManagers; 377 | @property (readonly, nonatomic) NSArray *writeOperationManagers; 378 | @property NSTimeInterval timeout; 379 | @property NSTimeInterval searchTimeout; 380 | @property (assign, nonatomic) BOOL startOperationsManually; 381 | 382 | /** 383 | * Add security tag header (see http://www.algolia.com/doc/guides/objc#SecurityUser for more details) 384 | */ 385 | @property (nonatomic) NSString *tagFilters; 386 | 387 | /** 388 | * Add user-token header (see http://www.algolia.com/doc/guides/objc#SecurityUser for more details) 389 | */ 390 | @property (nonatomic) NSString *userToken; 391 | 392 | @end 393 | -------------------------------------------------------------------------------- /src/ASAPIClient.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2013 Algolia 3 | // http://www.algolia.com/ 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 13 | // all 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 21 | // THE SOFTWARE. 22 | // 23 | 24 | #import "ASAPIClient.h" 25 | #import "ASAPIClient+Network.h" 26 | #import "ASRemoteIndex.h" 27 | 28 | 29 | NSString *const Version = @"3.7.0"; 30 | 31 | @implementation ASAPIClient 32 | 33 | +(instancetype) apiClientWithApplicationID:(NSString*)applicationID apiKey:(NSString*)apiKey hostnames:(NSArray*)hostnames 34 | { 35 | return [[self.class alloc] initWithApplicationID:applicationID apiKey:apiKey hostnames:hostnames tagFilters:nil userToken:nil]; 36 | } 37 | 38 | +(instancetype) apiClientWithApplicationID:(NSString*)applicationID apiKey:(NSString*)apiKey 39 | { 40 | return [[self.class alloc] initWithApplicationID:applicationID apiKey:apiKey hostnames:nil tagFilters:nil userToken:nil]; 41 | } 42 | 43 | -(instancetype) initWithApplicationID:(NSString*)papplicationID apiKey:(NSString*)papiKey hostnames:(NSArray*)phostnames tagFilters:(NSString*)tagFiltersHeader userToken:(NSString*)userTokenHeader 44 | { 45 | self = [super init]; 46 | if (self) { 47 | _applicationID = papplicationID; 48 | _apiKey = papiKey; 49 | _tagFilters = tagFiltersHeader; 50 | _userToken = userTokenHeader; 51 | _timeout = 30; 52 | _searchTimeout = 10; 53 | 54 | NSMutableArray *searchArray = nil; 55 | NSMutableArray *writeArray = nil; 56 | if (phostnames == nil) { 57 | searchArray = [NSMutableArray arrayWithObjects: 58 | [NSString stringWithFormat:@"%@-dsn.algolia.net", papplicationID], 59 | [NSString stringWithFormat:@"%@-1.algolianet.com", papplicationID], 60 | [NSString stringWithFormat:@"%@-2.algolianet.com", papplicationID], 61 | [NSString stringWithFormat:@"%@-3.algolianet.com", papplicationID], 62 | nil]; 63 | writeArray = [NSMutableArray arrayWithObjects: 64 | [NSString stringWithFormat:@"%@.algolia.net", papplicationID], 65 | [NSString stringWithFormat:@"%@-1.algolianet.com", papplicationID], 66 | [NSString stringWithFormat:@"%@-2.algolianet.com", papplicationID], 67 | [NSString stringWithFormat:@"%@-3.algolianet.com", papplicationID], 68 | nil]; 69 | } else { 70 | searchArray = writeArray = [NSMutableArray arrayWithArray:phostnames]; 71 | } 72 | 73 | _writeHostnames = writeArray; 74 | _searchHostnames = searchArray; 75 | 76 | if (self.applicationID == nil || [self.applicationID length] == 0) 77 | @throw [NSException exceptionWithName:@"InvalidArgument" reason:@"Application ID must be set" userInfo:nil]; 78 | if (self.apiKey == nil || [self.apiKey length] == 0) 79 | @throw [NSException exceptionWithName:@"InvalidArgument" reason:@"APIKey must be set" userInfo:nil]; 80 | if ([self.searchHostnames count] == 0) 81 | @throw [NSException exceptionWithName:@"InvalidArgument" reason:@"List of hosts must be set" userInfo:nil]; 82 | NSMutableArray *httpRequestOperationManagers = [[NSMutableArray alloc] init]; 83 | //NSString *version = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; TODO nil 84 | for (NSString *host in self.searchHostnames) { 85 | NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"https://%@", host]]; 86 | AFHTTPRequestOperationManager *httpRequestOperationManager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:url]; 87 | httpRequestOperationManager.responseSerializer = [AFJSONResponseSerializer serializer]; 88 | httpRequestOperationManager.requestSerializer = [AFJSONRequestSerializer serializer]; 89 | [httpRequestOperationManager.requestSerializer setValue:self.apiKey forHTTPHeaderField:@"X-Algolia-API-Key"]; 90 | [httpRequestOperationManager.requestSerializer setValue:self.applicationID forHTTPHeaderField:@"X-Algolia-Application-Id"]; 91 | [httpRequestOperationManager.requestSerializer setValue:[NSString stringWithFormat:@"Algolia for Objective-C %@", Version] forHTTPHeaderField:@"User-Agent"]; 92 | if (self.tagFilters != nil) { 93 | [httpRequestOperationManager.requestSerializer setValue:self.tagFilters forHTTPHeaderField:@"X-Algolia-TagFilters"]; 94 | } 95 | if (self.userToken != nil) { 96 | [httpRequestOperationManager.requestSerializer setValue:self.userToken forHTTPHeaderField:@"X-Algolia-UserToken"]; 97 | } 98 | [httpRequestOperationManagers addObject:httpRequestOperationManager]; 99 | } 100 | _writeOperationManagers = httpRequestOperationManagers; 101 | 102 | httpRequestOperationManagers = [[NSMutableArray alloc] init]; 103 | for (NSString *host in self.searchHostnames) { 104 | NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"https://%@", host]]; 105 | AFHTTPRequestOperationManager *httpRequestOperationManager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:url]; 106 | httpRequestOperationManager.responseSerializer = [AFJSONResponseSerializer serializer]; 107 | httpRequestOperationManager.requestSerializer = [AFJSONRequestSerializer serializer]; 108 | [httpRequestOperationManager.requestSerializer setValue:self.apiKey forHTTPHeaderField:@"X-Algolia-API-Key"]; 109 | [httpRequestOperationManager.requestSerializer setValue:self.applicationID forHTTPHeaderField:@"X-Algolia-Application-Id"]; 110 | [httpRequestOperationManager.requestSerializer setValue:[NSString stringWithFormat:@"Algolia for Objective-C %@", Version] forHTTPHeaderField:@"User-Agent"]; 111 | if (self.tagFilters != nil) { 112 | [httpRequestOperationManager.requestSerializer setValue:self.tagFilters forHTTPHeaderField:@"X-Algolia-TagFilters"]; 113 | } 114 | if (self.userToken != nil) { 115 | [httpRequestOperationManager.requestSerializer setValue:self.userToken forHTTPHeaderField:@"X-Algolia-UserToken"]; 116 | } 117 | [httpRequestOperationManagers addObject:httpRequestOperationManager]; 118 | } 119 | _searchOperationManagers = httpRequestOperationManagers; 120 | } 121 | return self; 122 | } 123 | 124 | -(void) setExtraHeader:(NSString*)value forHeaderField:key 125 | { 126 | for (AFHTTPRequestOperationManager *manager in self.writeOperationManagers) { 127 | [manager.requestSerializer setValue:value forHTTPHeaderField:key]; 128 | } 129 | for (AFHTTPRequestOperationManager *manager in self.searchOperationManagers) { 130 | [manager.requestSerializer setValue:value forHTTPHeaderField:key]; 131 | } 132 | } 133 | 134 | -(AFHTTPRequestOperation *) multipleQueries:(NSArray*)queries 135 | success:(void(^)(ASAPIClient *client, NSArray *queries, NSDictionary *result))success 136 | failure:(void(^)(ASAPIClient *client, NSArray *queries, NSString *errorMessage))failure 137 | { 138 | return [self multipleQueries:queries withStrategy:@"none" success:^(ASAPIClient *client, NSArray *queries, NSString *strategy, NSDictionary *result) { 139 | if (success != nil) 140 | success(client, queries, result); 141 | } failure:^(ASAPIClient *client, NSArray *queries, NSString *strategy, NSString *errorMessage) { 142 | if (failure != nil) 143 | failure(client, queries, errorMessage); 144 | }]; 145 | } 146 | 147 | -(AFHTTPRequestOperation *) multipleQueries:(NSArray*)queries withStrategy:(NSString*)strategy 148 | success:(void(^)(ASAPIClient *client, NSArray *queries, NSString* strategy, NSDictionary *result))success 149 | failure: (void(^)(ASAPIClient *client, NSArray *queries, NSString* strategy, NSString *errorMessage))failure 150 | { 151 | NSMutableArray *queriesTab =[[NSMutableArray alloc] initWithCapacity:[queries count]]; 152 | int i = 0; 153 | for (NSDictionary *query in queries) { 154 | NSString *queryParams = [query[@"query"] buildURL]; 155 | queriesTab[i++] = @{@"params": queryParams, @"indexName": query[@"indexName"]}; 156 | } 157 | NSString *path = [NSString stringWithFormat:@"/1/indexes/*/queries?strategy=%@", strategy]; 158 | NSMutableDictionary *request = [NSMutableDictionary dictionaryWithObject:queriesTab forKey:@"requests"]; 159 | return [self performHTTPQuery:path method:@"POST" body:request managers:self.searchOperationManagers index:0 timeout:self.searchTimeout success:^(id JSON) { 160 | if (success != nil) 161 | success(self, queries, strategy, JSON); 162 | } failure:^(NSString *errorMessage) { 163 | if (failure != nil) 164 | failure(self, queries, strategy, errorMessage); 165 | }]; 166 | } 167 | 168 | -(AFHTTPRequestOperation *) listIndexes:(void(^)(ASAPIClient *client, NSDictionary* result))success 169 | failure:(void(^)(ASAPIClient *client, NSString *errorMessage))failure 170 | { 171 | return [self performHTTPQuery:@"/1/indexes" method:@"GET" body:nil managers:self.searchOperationManagers index:0 timeout:self.timeout success:^(id JSON) { 172 | success(self, JSON); 173 | } failure:^(NSString *errorMessage) { 174 | failure(self, errorMessage); 175 | }]; 176 | } 177 | 178 | -(AFHTTPRequestOperation *) moveIndex:(NSString*)srcIndexName 179 | to:(NSString*)dstIndexName 180 | success:(void(^)(ASAPIClient *client, NSString *srcIndexName, NSString *dstIndexName, NSDictionary *result))success 181 | failure:(void(^)(ASAPIClient *client, NSString *srcIndexName, NSString *dstIndexName, NSString *errorMessage))failure 182 | { 183 | NSString *path = [NSString stringWithFormat:@"/1/indexes/%@/operation", [ASAPIClient urlEncode:srcIndexName]]; 184 | NSDictionary *request = @{@"destination": dstIndexName, @"operation": @"move"}; 185 | return [self performHTTPQuery:path method:@"POST" body:request managers:self.writeOperationManagers index:0 timeout:self.timeout success:^(id JSON) { 186 | if (success != nil) 187 | success(self, srcIndexName, dstIndexName, JSON); 188 | } failure:^(NSString *errorMessage) { 189 | if (failure != nil) 190 | failure(self, srcIndexName, dstIndexName,errorMessage); 191 | }]; 192 | } 193 | 194 | -(AFHTTPRequestOperation *) copyIndex:(NSString*)srcIndexName 195 | to:(NSString*)dstIndexName 196 | success:(void(^)(ASAPIClient *client, NSString *srcIndexName, NSString *dstIndexName, NSDictionary *result))success 197 | failure:(void(^)(ASAPIClient *client, NSString *srcIndexName, NSString *dstIndexName, NSString *errorMessage))failure 198 | { 199 | NSString *path = [NSString stringWithFormat:@"/1/indexes/%@/operation", [ASAPIClient urlEncode:srcIndexName]]; 200 | NSDictionary *request = @{@"destination": dstIndexName, @"operation": @"copy"}; 201 | return [self performHTTPQuery:path method:@"POST" body:request managers:self.writeOperationManagers index:0 timeout:self.timeout success:^(id JSON) { 202 | if (success != nil) 203 | success(self, srcIndexName, dstIndexName, JSON); 204 | } failure:^(NSString *errorMessage) { 205 | if (failure != nil) 206 | failure(self, srcIndexName, dstIndexName,errorMessage); 207 | }]; 208 | } 209 | 210 | -(AFHTTPRequestOperation *) getLogs:(void(^)(ASAPIClient *client, NSDictionary *result))success 211 | failure:(void(^)(ASAPIClient *client, NSString *errorMessage))failure 212 | { 213 | return [self performHTTPQuery:@"/1/logs" method:@"GET" body:nil managers:self.writeOperationManagers index:0 timeout:self.timeout success:^(id JSON) { 214 | success(self, JSON); 215 | } failure:^(NSString *errorMessage) { 216 | failure(self, errorMessage); 217 | }]; 218 | } 219 | 220 | -(AFHTTPRequestOperation *) getLogsWithOffset:(NSUInteger)offset 221 | length:(NSUInteger)length 222 | success:(void(^)(ASAPIClient *client, NSUInteger offset, NSUInteger length, NSDictionary *result))success 223 | failure:(void(^)(ASAPIClient *client, NSUInteger offset, NSUInteger length, NSString *errorMessage))failure 224 | { 225 | NSString *url = [NSString stringWithFormat:@"/1/logs?offset=%zd&length=%zd", offset, length]; 226 | return [self performHTTPQuery:url method:@"GET" body:nil managers:self.writeOperationManagers index:0 timeout:self.timeout success:^(id JSON) { 227 | success(self, offset, length, JSON); 228 | } failure:^(NSString *errorMessage) { 229 | failure(self, offset, length, errorMessage); 230 | }]; 231 | } 232 | 233 | -(AFHTTPRequestOperation *) getLogsWithType:(NSUInteger)offset 234 | length:(NSUInteger)length 235 | type:(NSString*)type 236 | success:(void(^)(ASAPIClient *client, NSUInteger offset, NSUInteger length, NSString* type, NSDictionary *result))success 237 | failure:(void(^)(ASAPIClient *client, NSUInteger offset, NSUInteger length, NSString* type, NSString *errorMessage))failure 238 | { 239 | NSString *url = [NSString stringWithFormat:@"/1/logs?offset=%zd&length=%zd&type=%@", offset, length, type]; 240 | return [self performHTTPQuery:url method:@"GET" body:nil managers:self.writeOperationManagers index:0 timeout:self.timeout success:^(id JSON) { 241 | success(self, offset, length, type, JSON); 242 | } failure:^(NSString *errorMessage) { 243 | failure(self, offset, length, type, errorMessage); 244 | }]; 245 | } 246 | 247 | -(AFHTTPRequestOperation *) deleteIndex:(NSString*)indexName 248 | success:(void(^)(ASAPIClient *client, NSString *indexName, NSDictionary *result))success 249 | failure:(void(^)(ASAPIClient *client, NSString *indexName, NSString *errorMessage))failure 250 | { 251 | NSString *path = [NSString stringWithFormat:@"/1/indexes/%@", [ASAPIClient urlEncode:indexName]]; 252 | 253 | return [self performHTTPQuery:path method:@"DELETE" body:nil managers:self.writeOperationManagers index:0 timeout:self.timeout success:^(id JSON) { 254 | if (success != nil) 255 | success(self, indexName, JSON); 256 | } failure:^(NSString *errorMessage) { 257 | if (failure != nil) 258 | failure(self, indexName, errorMessage); 259 | }]; 260 | } 261 | 262 | -(AFHTTPRequestOperation *) listUserKeys:(void(^)(ASAPIClient *client, NSDictionary* result))success 263 | failure:(void(^)(ASAPIClient *client, NSString *errorMessage))failure 264 | { 265 | return [self performHTTPQuery:@"/1/keys" method:@"GET" body:nil managers:self.searchOperationManagers index:0 timeout:self.timeout success:^(id JSON) { 266 | success(self, JSON); 267 | } failure:^(NSString *errorMessage) { 268 | failure(self, errorMessage); 269 | }]; 270 | } 271 | 272 | -(AFHTTPRequestOperation *) getUserKeyACL:(NSString*)key 273 | success:(void(^)(ASAPIClient *client, NSString *key, NSDictionary *result))success 274 | failure:(void(^)(ASAPIClient *client, NSString *key, NSString *errorMessage))failure 275 | { 276 | NSString *path = [NSString stringWithFormat:@"/1/keys/%@", key]; 277 | return [self performHTTPQuery:path method:@"GET" body:nil managers:self.searchOperationManagers index:0 timeout:self.timeout success:^(id JSON) { 278 | if (success != nil) 279 | success(self, key, JSON); 280 | } failure:^(NSString *errorMessage) { 281 | if (failure != nil) 282 | failure(self, key, errorMessage); 283 | }]; 284 | } 285 | 286 | -(AFHTTPRequestOperation *) deleteUserKey:(NSString*)key 287 | success:(void(^)(ASAPIClient *client, NSString *key, NSDictionary *result))success 288 | failure:(void(^)(ASAPIClient *client, NSString *key, NSString *errorMessage))failure 289 | { 290 | NSString *path = [NSString stringWithFormat:@"/1/keys/%@", key]; 291 | return [self performHTTPQuery:path method:@"DELETE" body:nil managers:self.writeOperationManagers index:0 timeout:self.timeout success:^(id JSON) { 292 | if (success != nil) 293 | success(self, key, JSON); 294 | } failure:^(NSString *errorMessage) { 295 | if (failure != nil) 296 | failure(self, key, errorMessage); 297 | }]; 298 | } 299 | 300 | -(AFHTTPRequestOperation *) addUserKey:(NSArray*)acls 301 | success:(void(^)(ASAPIClient *client, NSArray* acls, NSDictionary *result))success 302 | failure:(void(^)(ASAPIClient *client, NSArray* acls, NSString *errorMessage))failure 303 | { 304 | NSDictionary *params = [NSMutableDictionary dictionaryWithObject:acls forKey:@"acl"]; 305 | 306 | return [self addUserKey:acls withParams:params success:^(ASAPIClient *client, NSArray* acls, NSDictionary* params, NSDictionary *result) { 307 | if (success != nil) 308 | success(client, acls, result); 309 | } failure:^(ASAPIClient *client, NSArray* acls, NSDictionary* params, NSString *errorMessage) { 310 | if (failure != nil) 311 | failure(client, acls, errorMessage); 312 | }]; 313 | } 314 | 315 | -(AFHTTPRequestOperation *) addUserKey:(NSArray*)acls 316 | withParams:(NSDictionary*)params 317 | success:(void(^)(ASAPIClient *client, NSArray* acls, NSDictionary* params, NSDictionary *result))success 318 | failure:(void(^)(ASAPIClient *client, NSArray* acls, NSDictionary* params, NSString *errorMessage))failure 319 | { 320 | [params setValue:acls forKey:@"acl"]; 321 | return [self performHTTPQuery:@"/1/keys" method:@"POST" body:params managers:self.writeOperationManagers index:0 timeout:self.timeout success:^(id JSON) { 322 | if (success != nil) 323 | success(self, acls, params, JSON); 324 | } failure:^(NSString *errorMessage) { 325 | if (failure != nil) 326 | failure(self, acls, params, errorMessage); 327 | }]; 328 | } 329 | 330 | -(AFHTTPRequestOperation *) addUserKey:(NSArray*)acls 331 | withValidity:(NSUInteger)validity 332 | maxQueriesPerIPPerHour:(NSUInteger)maxQueriesPerIPPerHour 333 | maxHitsPerQuery:(NSUInteger)maxHitsPerQuery 334 | success:(void(^)(ASAPIClient *client, NSArray *acls, NSDictionary *result))success 335 | failure:(void(^)(ASAPIClient *client, NSArray *acls, NSString *errorMessage))failure 336 | { 337 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:acls, @"acl", 338 | @(validity), @"validity", 339 | @(maxQueriesPerIPPerHour), @"maxQueriesPerIPPerHour", 340 | @(maxHitsPerQuery), @"maxHitsPerQuery", 341 | nil]; 342 | return [self addUserKey:acls withParams:dict success:^(ASAPIClient *client, NSArray* acls, NSDictionary* params, NSDictionary *result) { 343 | if (success != nil) 344 | success(client, acls, result); 345 | } failure:^(ASAPIClient *client, NSArray* acls, NSDictionary* params, NSString *errorMessage) { 346 | if (failure != nil) 347 | failure(client, acls, errorMessage); 348 | }]; 349 | } 350 | 351 | -(AFHTTPRequestOperation *) addUserKey:(NSArray*)acls 352 | withIndexes:(NSArray*)indexes 353 | withValidity:(NSUInteger)validity 354 | maxQueriesPerIPPerHour:(NSUInteger)maxQueriesPerIPPerHour 355 | maxHitsPerQuery:(NSUInteger)maxHitsPerQuery 356 | success:(void(^)(ASAPIClient *client, NSArray *acls, NSArray *indexes, NSDictionary *result))success 357 | failure:(void(^)(ASAPIClient *client, NSArray *acls, NSArray *indexes, NSString *errorMessage))failure 358 | { 359 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:acls, @"acl", indexes, @"indexes", 360 | @(validity), @"validity", 361 | @(maxQueriesPerIPPerHour), @"maxQueriesPerIPPerHour", 362 | @(maxHitsPerQuery), @"maxHitsPerQuery", 363 | nil]; 364 | return [self addUserKey:acls withParams:dict success:^(ASAPIClient *client, NSArray* acls, NSDictionary* params, NSDictionary *result) { 365 | if (success != nil) 366 | success(client, acls, indexes, result); 367 | } failure:^(ASAPIClient *client, NSArray* acls, NSDictionary* params, NSString *errorMessage) { 368 | if (failure != nil) 369 | failure(client, acls, indexes, errorMessage); 370 | }]; 371 | } 372 | 373 | -(AFHTTPRequestOperation *) updateUserKey:(NSString*)key 374 | withParams:(NSDictionary*)params 375 | success:(void(^)(ASAPIClient *client, NSString *key, NSDictionary *params, NSDictionary *result))success 376 | failure:(void(^)(ASAPIClient *client, NSString *key, NSDictionary *params, NSString *errorMessage))failure 377 | { 378 | NSString *path = [NSString stringWithFormat:@"/1/keys/%@", key]; 379 | return [self performHTTPQuery:path method:@"PUT" body:params managers:self.writeOperationManagers index:0 timeout:self.timeout success:^(id JSON) { 380 | if (success != nil) 381 | success(self, key, params, JSON); 382 | } failure:^(NSString *errorMessage) { 383 | if (failure != nil) 384 | failure(self, key, params, errorMessage); 385 | }]; 386 | } 387 | 388 | -(AFHTTPRequestOperation *) updateUserKey:(NSString*)key 389 | withACL:(NSArray*)acls 390 | success:(void(^)(ASAPIClient *client, NSString *key, NSArray *acls, NSDictionary *result))success 391 | failure:(void(^)(ASAPIClient *client, NSString *key, NSArray *acls, NSString *errorMessage))failure 392 | { 393 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObject:acls forKey:@"acl"]; 394 | return [self updateUserKey:key withParams:dict success:^(ASAPIClient *client, NSString *key, NSDictionary *params, NSDictionary *result) { 395 | if (success != nil) 396 | success(client, key, acls, result); 397 | } failure:^(ASAPIClient *client, NSString *key, NSDictionary *params, NSString *errorMessage) { 398 | if (failure != nil) 399 | failure(client, key, acls, errorMessage); 400 | }]; 401 | } 402 | 403 | -(AFHTTPRequestOperation *) updateUserKey:(NSString*)key 404 | withACL:(NSArray*)acls 405 | withValidity:(NSUInteger)validity 406 | maxQueriesPerIPPerHour:(NSUInteger)maxQueriesPerIPPerHour 407 | maxHitsPerQuery:(NSUInteger)maxHitsPerQuery 408 | success:(void(^)(ASAPIClient *client, NSString *key, NSArray *acls, NSDictionary *result))success 409 | failure:(void(^)(ASAPIClient *client, NSString *key, NSArray *acls, NSString *errorMessage))failure 410 | { 411 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:acls, @"acl", 412 | @(validity), @"validity", 413 | @(maxQueriesPerIPPerHour), @"maxQueriesPerIPPerHour", 414 | @(maxHitsPerQuery), @"maxHitsPerQuery", 415 | nil]; 416 | return [self updateUserKey:key withParams:dict success:^(ASAPIClient *client, NSString *key, NSDictionary *params, NSDictionary *result) { 417 | if (success != nil) 418 | success(client, key, acls, result); 419 | } failure:^(ASAPIClient *client, NSString *key, NSDictionary *params, NSString *errorMessage) { 420 | if (failure != nil) 421 | failure(client, key, acls, errorMessage); 422 | }]; 423 | } 424 | 425 | -(AFHTTPRequestOperation *) updateUserKey:(NSString*)key 426 | withACL:(NSArray*)acls 427 | withIndexes:(NSArray*)indexes 428 | withValidity:(NSUInteger)validity 429 | maxQueriesPerIPPerHour:(NSUInteger)maxQueriesPerIPPerHour 430 | maxHitsPerQuery:(NSUInteger)maxHitsPerQuery 431 | success:(void(^)(ASAPIClient *client, NSString *key, NSArray *acls, NSArray *indexes, NSDictionary *result))success 432 | failure:(void(^)(ASAPIClient *client, NSString *key, NSArray *acls, NSArray *indexes, NSString *errorMessage))failure 433 | { 434 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:acls, @"acl", indexes, @"indexes", 435 | @(validity), @"validity", 436 | @(maxQueriesPerIPPerHour), @"maxQueriesPerIPPerHour", 437 | @(maxHitsPerQuery), @"maxHitsPerQuery", 438 | nil]; 439 | return [self updateUserKey:key withParams:dict success:^(ASAPIClient *client, NSString *key, NSDictionary *params, NSDictionary *result) { 440 | if (success != nil) 441 | success(client, key, acls, indexes, result); 442 | } failure:^(ASAPIClient *client, NSString *key, NSDictionary *params, NSString *errorMessage) { 443 | if (failure != nil) 444 | failure(client, key, acls, indexes, errorMessage); 445 | }]; 446 | } 447 | 448 | -(AFHTTPRequestOperation *) batch:(NSDictionary*)requests 449 | success:(void(^)(ASAPIClient *client, NSDictionary *requests, NSDictionary *result))success 450 | failure:(void(^)(ASAPIClient *client, NSDictionary *requests, NSString *errorMessage))failure 451 | { 452 | NSDictionary *request = @{@"requests": requests}; 453 | return [self performHTTPQuery:@"/1/indexes/*/batch" method:@"POST" body:request managers:self.writeOperationManagers index:0 timeout:self.timeout success:^(id JSON) { 454 | if (success != nil) 455 | success(self, requests, JSON); 456 | } failure:^(NSString *errorMessage) { 457 | if (failure != nil) 458 | failure(self, requests, errorMessage); 459 | }]; 460 | } 461 | 462 | 463 | -(ASRemoteIndex*) getIndex:(NSString*)indexName 464 | { 465 | return [ASRemoteIndex remoteIndexWithAPIClient:self indexName:indexName]; 466 | } 467 | 468 | -(void) setTagFilters:(NSString *)tagFiltersHeader 469 | { 470 | _tagFilters = tagFiltersHeader; 471 | 472 | for (AFHTTPRequestOperationManager* manager in self.writeOperationManagers) { 473 | [manager.requestSerializer setValue:self.tagFilters forHTTPHeaderField:@"X-Algolia-TagFilters"]; 474 | } 475 | for (AFHTTPRequestOperationManager* manager in self.searchOperationManagers) { 476 | [manager.requestSerializer setValue:self.tagFilters forHTTPHeaderField:@"X-Algolia-TagFilters"]; 477 | } 478 | } 479 | 480 | -(void) setUserToken:(NSString *)userTokenHeader 481 | { 482 | _userToken = userTokenHeader; 483 | 484 | for (AFHTTPRequestOperationManager* manager in self.writeOperationManagers) { 485 | [manager.requestSerializer setValue:self.userToken forHTTPHeaderField:@"X-Algolia-UserToken"]; 486 | } 487 | for (AFHTTPRequestOperationManager* manager in self.searchOperationManagers) { 488 | [manager.requestSerializer setValue:self.userToken forHTTPHeaderField:@"X-Algolia-UserToken"]; 489 | } 490 | } 491 | 492 | @end 493 | -------------------------------------------------------------------------------- /src/ASBrowseIterator.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2013 Algolia 3 | // http://www.algolia.com/ 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 13 | // all 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 21 | // THE SOFTWARE. 22 | // 23 | 24 | #import 25 | 26 | @class ASRemoteIndex; 27 | @class ASQuery; 28 | 29 | @interface ASBrowseIterator : NSObject 30 | 31 | typedef void(^BrowseIteratorHandler)(ASBrowseIterator *iterator, BOOL end, NSString *error); 32 | 33 | - (instancetype)initWithIndex:(ASRemoteIndex*)index 34 | query:(ASQuery*)query 35 | cursor:(NSString*)cursor 36 | andBlock:(BrowseIteratorHandler)pblock; 37 | 38 | - (void)next; 39 | 40 | @property (nonatomic) ASRemoteIndex *index; 41 | @property (nonatomic) NSString *cursor; 42 | @property (nonatomic) NSDictionary *result; 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /src/ASBrowseIterator.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2013 Algolia 3 | // http://www.algolia.com/ 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 13 | // all 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 21 | // THE SOFTWARE. 22 | // 23 | 24 | #import "ASBrowseIterator.h" 25 | #import "ASAPIClient.h" 26 | #import "ASAPIClient+Network.h" 27 | #import "ASQuery.h" 28 | #import "ASRemoteIndex.h" 29 | 30 | 31 | @implementation ASBrowseIterator 32 | { 33 | NSString *path; 34 | NSString *queryURL; 35 | BrowseIteratorHandler block; 36 | BOOL end; 37 | } 38 | 39 | - (instancetype)initWithIndex:(ASRemoteIndex*)index 40 | query:(ASQuery*)query 41 | cursor:(NSString*)cursor 42 | andBlock:(BrowseIteratorHandler)pblock 43 | { 44 | self = [super init]; 45 | if (self) { 46 | _index = index; 47 | _cursor = (cursor != nil) ? cursor : nil; 48 | block = [pblock copy]; 49 | 50 | queryURL = (query != nil) ? [query buildURL] : @""; 51 | path = [NSString stringWithFormat:@"/1/indexes/%@/browse?", index.urlEncodedIndexName]; 52 | 53 | end = false; 54 | } 55 | return self; 56 | } 57 | 58 | - (void)next 59 | { 60 | NSMutableString *requestPath = [path mutableCopy]; 61 | if (self.cursor != nil) { 62 | [requestPath appendFormat:@"cursor=%@", [ASAPIClient urlEncode:self.cursor]]; 63 | } else { 64 | [requestPath appendString:queryURL]; 65 | } 66 | 67 | [self.index.apiClient performHTTPQuery:requestPath method:@"GET" body:nil managers:self.index.apiClient.searchOperationManagers index:0 timeout:self.index.apiClient.timeout success:^(id JSON) { 68 | self.result = JSON; 69 | self.cursor = JSON[@"cursor"]; 70 | if (self.cursor == nil) { 71 | end = true; 72 | } 73 | 74 | block(self, end, nil); 75 | } failure:^(NSString *errorMessage) { 76 | block(self, false, errorMessage); 77 | }]; 78 | } 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /src/ASExpiringCache.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2013 Algolia 3 | // http://www.algolia.com/ 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 13 | // all 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 21 | // THE SOFTWARE. 22 | // 23 | 24 | #import 25 | 26 | @interface ASExpiringCache : NSObject 27 | 28 | - (instancetype)initWithExpiringTimeInterval:(NSTimeInterval)eti; 29 | 30 | - (void)dealloc; 31 | 32 | - (NSDictionary*)objectForKey:(NSString*)key; 33 | 34 | - (void)setObject:(NSDictionary*)obj forKey:(NSString*)key; 35 | 36 | - (void)clearCache; 37 | 38 | - (void)clearExpiredCache; 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /src/ASExpiringCache.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2013 Algolia 3 | // http://www.algolia.com/ 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 13 | // all 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 21 | // THE SOFTWARE. 22 | // 23 | 24 | #import "ASExpiringCache.h" 25 | #import "ASExpiringCacheItem.h" 26 | 27 | @implementation ASExpiringCache { 28 | NSCache *cache; 29 | NSTimeInterval expiringTimeInterval; 30 | 31 | NSMutableArray *cacheKeys; 32 | NSTimer *timer; 33 | } 34 | 35 | - (instancetype)initWithExpiringTimeInterval:(NSTimeInterval)eti { 36 | self = [super init]; 37 | if (self) { 38 | expiringTimeInterval = eti; 39 | cache = [[NSCache alloc] init]; 40 | cacheKeys = [NSMutableArray array]; 41 | 42 | // Garbage collector like, for the expired cache 43 | timer = [NSTimer timerWithTimeInterval:(2 * eti) target:self selector:@selector(clearExpiredCache) userInfo:nil repeats:YES]; 44 | timer.tolerance = eti * 0.5; 45 | [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; 46 | } 47 | return self; 48 | } 49 | 50 | - (void)dealloc { 51 | [timer invalidate]; 52 | } 53 | 54 | - (NSDictionary*)objectForKey:(NSString*)key { 55 | ASExpiringCacheItem *object = [cache objectForKey:key]; 56 | if (object != nil) { 57 | if ([object hasExpired:expiringTimeInterval]) { 58 | [cache removeObjectForKey:key]; 59 | } else { 60 | return object.content; 61 | } 62 | } 63 | 64 | return nil; 65 | } 66 | 67 | - (void)setObject:(NSDictionary*)obj forKey:(NSString*)key { 68 | [cache setObject:[ASExpiringCacheItem newItem:obj] forKey:key]; 69 | [cacheKeys addObject:key]; 70 | } 71 | 72 | - (void)clearCache { 73 | [cache removeAllObjects]; 74 | [cacheKeys removeAllObjects]; 75 | } 76 | 77 | - (void)clearExpiredCache { 78 | NSMutableArray *tmp = [NSMutableArray array]; 79 | 80 | for (int i = 0; i < [cacheKeys count]; ++i) { 81 | ASExpiringCacheItem *object = [cache objectForKey:cacheKeys[i]]; 82 | if (object != nil) { 83 | if ([object hasExpired:expiringTimeInterval]) { 84 | [cache removeObjectForKey:cacheKeys[i]]; 85 | } else { 86 | [tmp addObject:cacheKeys[i]]; 87 | } 88 | } 89 | } 90 | 91 | cacheKeys = tmp; 92 | } 93 | 94 | @end 95 | -------------------------------------------------------------------------------- /src/ASExpiringCacheItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2013 Algolia 3 | // http://www.algolia.com/ 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 13 | // all 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 21 | // THE SOFTWARE. 22 | // 23 | 24 | #import 25 | 26 | @interface ASExpiringCacheItem : NSObject 27 | 28 | + (instancetype)newItem:(NSDictionary*)content; 29 | 30 | - (BOOL)hasExpired:(NSTimeInterval)expiringTimeInterval; 31 | 32 | @property (nonatomic) NSDictionary *content; 33 | @property (nonatomic) NSDate *expiringCacheItemDate; 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /src/ASExpiringCacheItem.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2013 Algolia 3 | // http://www.algolia.com/ 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 13 | // all 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 21 | // THE SOFTWARE. 22 | // 23 | 24 | #import "ASExpiringCacheItem.h" 25 | 26 | @interface ASExpiringCacheItem () 27 | 28 | - (instancetype)initWithContent:(NSDictionary*)content; 29 | 30 | @end 31 | 32 | @implementation ASExpiringCacheItem 33 | 34 | + (instancetype)newItem:(NSDictionary*)content { 35 | return [[self.class alloc] initWithContent:content]; 36 | } 37 | 38 | - (instancetype)initWithContent:(NSDictionary*)content { 39 | self = [super init]; 40 | if (self) { 41 | _content = content; 42 | _expiringCacheItemDate = [NSDate date]; 43 | } 44 | return self; 45 | } 46 | 47 | - (BOOL)hasExpired:(NSTimeInterval)expiringTimeInterval { 48 | return fabs([self.expiringCacheItemDate timeIntervalSinceNow]) > expiringTimeInterval; 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /src/ASQuery.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2013 Algolia 3 | // http://www.algolia.com/ 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 13 | // all 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 21 | // THE SOFTWARE. 22 | // 23 | 24 | #import 25 | 26 | /** 27 | * Describes all parameters of search query. 28 | */ 29 | @interface ASQuery : NSObject 30 | 31 | /** 32 | * Initialize query with a full text query string 33 | */ 34 | +(instancetype) queryWithFullTextQuery:(NSString*)fullTextQuery; 35 | 36 | /** 37 | * Initialize an empty query 38 | */ 39 | -(instancetype) init; 40 | 41 | /** 42 | * Initialize query with a full text query string 43 | */ 44 | -(instancetype) initWithFullTextQuery:(NSString*)fullTextQuery; 45 | 46 | -(instancetype) copyWithZone:(NSZone*)zone; 47 | 48 | /** 49 | * Search for entries around a given latitude/longitude with an automatic radius 50 | */ 51 | -(ASQuery*) searchAroundLatitude:(float)latitude longitude:(float)longitude; 52 | 53 | /** 54 | * Search for entries around a given latitude/longitude. 55 | * 56 | * @param maxDist set the maximum distance in meters. 57 | * Note: at indexing, geoloc of an object should be set with _geoloc attribute containing lat and lng attributes (for example {"_geoloc":{"lat":48.853409, "lng":2.348800}}) 58 | */ 59 | -(ASQuery*) searchAroundLatitude:(float)latitude longitude:(float)longitude maxDist:(NSUInteger)maxDist; 60 | 61 | /** 62 | * Search for entries around a given latitude/longitude. 63 | * 64 | * @param maxDist set the maximum distance in meters. 65 | * @param precision set the precision for ranking (for example if you set precision=100, two objects that are distant of less than 100m will be considered as identical for "geo" ranking parameter). 66 | * Note: at indexing, geoloc of an object should be set with _geoloc attribute containing lat and lng attributes (for example {"_geoloc":{"lat":48.853409, "lng":2.348800}}) 67 | */ 68 | -(ASQuery*) searchAroundLatitude:(float)latitude longitude:(float)longitude maxDist:(NSUInteger)maxDist precision:(NSUInteger)precision; 69 | 70 | /** 71 | * Search for entries around a given latitude/longitude (using IP geolocation) with an automatic radius 72 | */ 73 | -(ASQuery*) searchAroundLatitudeLongitudeViaIP; 74 | 75 | /** 76 | * Search for entries around a given latitude/longitude (using IP geolocation) 77 | * 78 | * @param maxDist set the maximum distance in meters. 79 | * Note: at indexing, geoloc of an object should be set with _geoloc attribute containing lat and lng attributes (for example {"_geoloc":{"lat":48.853409, "lng":2.348800}}) 80 | */ 81 | -(ASQuery*) searchAroundLatitudeLongitudeViaIP:(NSUInteger)maxDist; 82 | 83 | /** 84 | * Search for entries around a given latitude/longitude (using IP geolocation) 85 | * 86 | * @param maxDist set the maximum distance in meters. 87 | * @param precision set the precision for ranking (for example if you set precision=100, two objects that are distant of less than 100m will be considered as identical for "geo" ranking parameter). 88 | * Note: at indexing, geoloc of an object should be set with _geoloc attribute containing lat and lng attributes (for example {"_geoloc":{"lat":48.853409, "lng":2.348800}}) 89 | */ 90 | -(ASQuery*) searchAroundLatitudeLongitudeViaIP:(NSUInteger)maxDist precision:(NSUInteger)precision; 91 | 92 | 93 | /** 94 | * Search for entries inside a given area defined by the two extreme points of a rectangle. 95 | * At indexing, you should specify geoloc of an object with the _geoloc attribute (in the form "_geoloc":{"lat":48.853409, "lng":2.348800} or 96 | * "_geoloc":[{"lat":48.853409, "lng":2.348800},{"lat":48.547456, "lng":2.972075}] if you have several geo-locations in your record). 97 | * 98 | * You can use several bounding boxes (OR) by calling this method several times. 99 | */ 100 | -(ASQuery*) searchInsideBoundingBoxWithLatitudeP1:(float)latitudeP1 longitudeP1:(float)longitudeP1 latitudeP2:(float)latitudeP2 longitudeP2:(float)longitudeP2; 101 | 102 | /** 103 | * Add a point to the polygon of geo-search (requires a minimum of three points to define a valid polygon) 104 | * At indexing, you should specify geoloc of an object with the _geoloc attribute (in the form "_geoloc":{"lat":48.853409, "lng":2.348800} or 105 | * "_geoloc":[{"lat":48.853409, "lng":2.348800},{"lat":48.547456, "lng":2.972075}] if you have several geo-locations in your record). 106 | */ 107 | -(ASQuery*) addInsidePolygon:(float)latitude longitude:(float)longitude; 108 | 109 | /** 110 | * Return the final query string used in URL. 111 | */ 112 | -(NSString*) buildURL; 113 | 114 | /** 115 | * Set a parameter by name and string value. 116 | * 117 | * WARNING: Parameters set this way override any conflicting typed property. No consistency check is performed. 118 | * Whenever available, the typed property should be preferred. 119 | */ 120 | - (void)set:(NSString * _Nonnull)name value:(NSString * _Nullable)value; 121 | 122 | /** 123 | * Get the value of an extra parameter. 124 | * 125 | * WARNING: Only parameters set using `-[ASQuery set:value:]` (or the subscript operator) can be read this way. 126 | */ 127 | - (NSString * _Nullable)get:(NSString * _Nonnull)name; 128 | 129 | /** 130 | * Subscript assignment operator. Convenience shortcut for `-[ASQuery set:value:]`. 131 | */ 132 | - (void)setObject:(NSString * _Nullable)newValue forKeyedSubscript:(NSString * _Nonnull)index; 133 | 134 | /** 135 | * Subscript read operator. Convenience shortcut for `-[ASQuery get:]`. 136 | */ 137 | - (NSString * _Nullable)objectForKeyedSubscript:(NSString * _Nonnull)index; 138 | 139 | /** 140 | * Select how the query words are interpreted: 141 | * "prefixAll": all query words are interpreted as prefixes, 142 | * "prefixLast": only the last word is interpreted as a prefix (default behavior), 143 | * "prefixNone": no query word is interpreted as a prefix. This option is not recommended. 144 | */ 145 | @property (nonatomic) NSString *queryType; 146 | 147 | /** 148 | * Set full text search of similar query (like this) 149 | */ 150 | @property (nonatomic) NSString *similarQuery; 151 | 152 | /** 153 | * Select the strategy to avoid having an empty result page. 154 | * "None": No specific processing is done when a query does not return any result, 155 | * "LastWords": when a query does not return any result, the final word will be removed until there is results, 156 | * "FirstWords": when a query does not return any result, the first word will be removed until there is results. 157 | * "allOptional": When a query does not return any result, a second trial will be made with all words as optional (which is equivalent to transforming the AND operand between query terms in a OR operand) 158 | */ 159 | @property (nonatomic) NSString *removeWordsIfNoResult; 160 | 161 | /** 162 | * Specify the list of attribute names to retrieve. 163 | * By default all attributes are retrieved. 164 | */ 165 | @property (nonatomic) NSArray *attributesToRetrieve; 166 | 167 | /** 168 | * Specify the list of attribute names to highlight. 169 | * By default indexed attributes are highlighted. 170 | */ 171 | @property (nonatomic) NSArray *attributesToHighlight; 172 | 173 | /** 174 | * Specify the List of attributes on which you want to disable typo tolerance (must be a subset of the attributesToIndex index setting). 175 | * By default this list is empty 176 | */ 177 | @property (nonatomic) NSArray *disableTypoToleranceOnAttributes; 178 | 179 | /** 180 | * Specify the list of attributes to snippet alongside the number of words to return 181 | * (syntax is 'attributeName:nbWords'). 182 | * Attributes are separated by a comma (Example: "attributesToSnippet=name:10,content:10"). 183 | * By default no snippet is computed. 184 | */ 185 | @property (nonatomic) NSArray *attributesToSnippet; 186 | 187 | /** 188 | * Filter the query by a set of tags. You can AND tags by separating them by commas. To OR tags, you must add parentheses. For example tag1,(tag2,tag3) means tag1 AND (tag2 OR tag3). 189 | * At indexing, tags should be added in the _tags attribute of objects (for example {"_tags":["tag1","tag2"]} ) 190 | */ 191 | @property (nonatomic) NSString *tagFilters; 192 | 193 | /** 194 | * Add a list of numeric filters separated by a comma. 195 | * The syntax of one filter is `attributeName` followed by `operand` followed by `value. Supported operands are `<`, `<=`, `=`, `>` and `>=`. 196 | * You can have multiple conditions on one attribute like for example `numerics=price>100,price<1000`. 197 | */ 198 | @property (nonatomic) NSString *numericFilters; 199 | 200 | /** 201 | * Set the full text query. 202 | */ 203 | @property (nonatomic) NSString *fullTextQuery; 204 | 205 | /** 206 | * Specify the minimum number of characters in a query word to accept one typo in this word. 207 | * Defaults to 3. 208 | */ 209 | @property (nonatomic) NSUInteger minWordSizeForApprox1; 210 | 211 | /** 212 | * Specify the minimum number of characters in a query word to accept two typos in this word. 213 | * Defaults to 7. 214 | */ 215 | @property (nonatomic) NSUInteger minWordSizeForApprox2; 216 | 217 | /** 218 | * Set the page to retrieve (zero base). Defaults to 0. 219 | */ 220 | @property (nonatomic) NSUInteger page; 221 | 222 | /** 223 | * Set the number of hits per page. Defaults to 10. 224 | */ 225 | @property (nonatomic) NSUInteger hitsPerPage; 226 | 227 | /** 228 | * Configure the precision of the proximity ranking criterion. By default, the minimum (and best) proximity value distance between 2 matching words is 1. Setting it to 2 (or 3) would allow 1 (or 2) words to be found between the matching words without degrading the proximity ranking value. 229 | * Considering the query "javascript framework", if you set minProximity=2 the records "JavaScript framework" and "JavaScript charting framework" will get the same proximity score, even if the second one contains a word between the 2 matching words. Default to 1. 230 | */ 231 | @property (nonatomic) NSUInteger minProximity; 232 | 233 | /** 234 | * if set, the result hits will contain ranking information in _rankingInfo attribute. 235 | */ 236 | @property BOOL getRankingInfo; 237 | 238 | /** 239 | * If set to YES, plural won't be considered as a typo (for example car/cars will be considered as equals). Default to NO. 240 | */ 241 | @property BOOL ignorePlural; 242 | 243 | /** 244 | * This option allow to control the number of typo in the results set. 245 | */ 246 | @property (nonatomic) NSString *typoTolerance; 247 | 248 | /** 249 | * If set to false, disable typo-tolerance on numeric tokens. Default to true. 250 | */ 251 | @property BOOL typosOnNumericTokens; 252 | 253 | /** 254 | * If set to false, disable this query won't appear in the analytics. Default to true. 255 | */ 256 | @property BOOL analytics; 257 | 258 | /** 259 | * If set to false, this query will not use synonyms defined in configuration. Default to true. 260 | */ 261 | @property BOOL synonyms; 262 | 263 | /** 264 | * If set to false, words matched via synonyms expansion will not be replaced by the matched synonym in highlight result. Default to true. 265 | */ 266 | @property BOOL replaceSynonyms; 267 | 268 | /** 269 | * 270 | * Enable the distinct feature (disabled by default) if the attributeForDistinct index setting is set. 271 | * This feature is similar to the SQL "distinct" keyword: when enabled in a query with the distinct=1 parameter, 272 | * all hits containing a duplicate value for the attributeForDistinct attribute are removed from results. 273 | * For example, if the chosen attribute is show_name and several hits have the same value for show_name, 274 | * then only the best one is kept and others are removed. 275 | * Specify the maximum number of hits to keep for each distinct value. 276 | */ 277 | @property (nonatomic) NSUInteger distinct; 278 | 279 | /** 280 | * Set the list of words that should be considered as optional when found in the query (array of NSString). 281 | */ 282 | @property (nonatomic) NSArray *optionalWords; 283 | 284 | /** 285 | * Set the minimum number of optional words that need to match 286 | */ 287 | @property (nonatomic) NSUInteger optionalWordsMinimumMatched; 288 | 289 | /** 290 | * Filter the query with numeric, facet or/and tag filters. The syntax is a SQL like syntax, you can use the OR and AND keywords. 291 | * The syntax for the underlying numeric, facet and tag filters is the same than in the other filters: 292 | * available=1 AND (category:Book OR NOT category:Ebook) AND public 293 | * date: 1441745506 TO 1441755506 AND inStock > 0 AND author:"John Doe" 294 | * The list of keywords is: 295 | * OR: create a disjunctive filter between two filters. 296 | * AND: create a conjunctive filter between two filters. 297 | * TO: used to specify a range for a numeric filter. 298 | * NOT: used to negate a filter. The syntax with the ‘-‘ isn’t allowed. 299 | */ 300 | @property (nonatomic) NSString *filters; 301 | 302 | /** 303 | * Filter the query by a list of facets. Each facet is encoded as `attributeName:value`. For example: ["category:Book","author:John%20Doe"]. 304 | */ 305 | @property (nonatomic) NSArray *facetFilters; 306 | 307 | /** 308 | * Filter the query by a list of facets encoded as one string by example "(category:Book,author:John)" 309 | */ 310 | @property (nonatomic) NSString *facetFiltersRaw; 311 | 312 | /** 313 | * List of object attributes that you want to use for faceting. 314 | * Only attributes that have been added in **attributesForFaceting** index setting can be used in this parameter. 315 | * You can also use `*` to perform faceting on all attributes specified in **attributesForFaceting**. 316 | */ 317 | @property (nonatomic) NSArray *facets; 318 | 319 | /** 320 | * List of object attributes you want to use for textual search (must be a subset of the attributesToIndex 321 | * index setting). Attributes are separated with a comma (for example @"name,address"). 322 | * You can also use a JSON string array encoding (for example encodeURIComponent("[\"name\",\"address\"]")). 323 | * By default, all attributes specified in attributesToIndex settings are used to search. 324 | */ 325 | @property (nonatomic) NSString *restrictSearchableAttributes; 326 | 327 | /** 328 | * Specify the string that is inserted before the highlighted parts in the query result (default to ""). 329 | */ 330 | @property (nonatomic) NSString *highlightPreTag; 331 | 332 | /** 333 | * Specify the string that is inserted after the highlighted parts in the query result (default to ""). 334 | */ 335 | @property (nonatomic) NSString *highlightPostTag; 336 | 337 | /** 338 | * Specify the string that is used as an ellipsis indicator when a snippet 339 | * is truncated (defaults to the empty string). 340 | */ 341 | @property (nonatomic) NSString *snippetEllipsisText; 342 | 343 | /** 344 | * Contains insideBoundingBox query (you should use searchInsideBoundingBox selector to set it) 345 | */ 346 | @property (nonatomic) NSString *insideBoundingBox; 347 | 348 | /** 349 | * Contains insidePolygon query (you should use addInsidePolygon selector to set it) 350 | */ 351 | @property (nonatomic) NSString *insidePolygon; 352 | 353 | /** 354 | * Contains aroundLatLong query (you should use searchAroundLatitude:longitude:maxDist selector to set it) 355 | */ 356 | @property (nonatomic) NSString *aroundLatLong; 357 | 358 | /** 359 | * Change the radius or around latitude/longitude query 360 | */ 361 | @property (nonatomic) NSUInteger aroundRadius; 362 | 363 | /** 364 | * Change the precision or around latitude/longitude query 365 | */ 366 | @property (nonatomic) NSUInteger aroundPrecision; 367 | 368 | /** 369 | * Tags can be used in the Analytics to analyze a subset of searches only. Comma-separated string list like @[@"ios", @"web"] 370 | */ 371 | @property (nonatomic) NSArray *analyticsTags; 372 | 373 | /** 374 | * If set to YES use geolocation via client IP instead of passing a latitude/longitude manually 375 | */ 376 | @property BOOL aroundLatLongViaIP; 377 | 378 | /** 379 | * If set to YES, the advanced query syntax will be availabel. Default to false. 380 | */ 381 | @property BOOL advancedSyntax; 382 | 383 | /** 384 | * If set to YES, enable removal of stop words 385 | */ 386 | @property BOOL removeStopWords; 387 | 388 | /** 389 | * 390 | */ 391 | @property (nonatomic) NSString *userToken; 392 | 393 | /** 394 | * 395 | */ 396 | @property (nonatomic) NSString *referers; 397 | 398 | /** 399 | * Define the maximum number of values returns foreach facet 400 | */ 401 | @property (nonatomic) NSUInteger maxValuesPerFacet; 402 | 403 | @end 404 | -------------------------------------------------------------------------------- /src/ASQuery.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2013 Algolia 3 | // http://www.algolia.com/ 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 13 | // all 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 21 | // THE SOFTWARE. 22 | // 23 | 24 | #import "ASQuery.h" 25 | #import "ASAPIClient+Network.h" 26 | 27 | @implementation ASQuery { 28 | BOOL minWordSizeForApprox1Set; 29 | BOOL minWordSizeForApprox2Set; 30 | BOOL hitsPerPageSet; 31 | BOOL minProximitySet; 32 | BOOL getRankingInfoSet; 33 | BOOL ignorePluralSet; 34 | BOOL typosOnNumericTokensSet; 35 | BOOL analyticsSet; 36 | BOOL synonymsSet; 37 | BOOL replaceSynonymsSet; 38 | BOOL distinctSet; 39 | BOOL optionalWordsMinimumMatchedSet; 40 | BOOL aroundRadiusSet; 41 | BOOL aroundPrecisionSet; 42 | BOOL aroundLatLongViaIPSet; 43 | BOOL advancedSyntaxSet; 44 | BOOL removeStopWordsSet; 45 | BOOL maxValuesPerFacetSet; 46 | NSMutableDictionary* _parameters; 47 | } 48 | 49 | +(instancetype) queryWithFullTextQuery:(NSString *)fullTextQuery 50 | { 51 | return [[ASQuery alloc] initWithFullTextQuery:fullTextQuery]; 52 | } 53 | 54 | -(instancetype) init 55 | { 56 | return [self initWithFullTextQuery:nil]; 57 | } 58 | 59 | -(instancetype) initWithFullTextQuery:(NSString *)pfullTextQuery 60 | { 61 | self = [super init]; 62 | if (self) { 63 | _parameters = [NSMutableDictionary dictionary]; 64 | minWordSizeForApprox1Set = minWordSizeForApprox2Set = getRankingInfoSet = ignorePluralSet = distinctSet = hitsPerPageSet = minProximitySet = maxValuesPerFacetSet = NO; 65 | typosOnNumericTokensSet = analyticsSet = synonymsSet = replaceSynonymsSet = optionalWordsMinimumMatchedSet = aroundLatLongViaIPSet = NO; 66 | advancedSyntaxSet = removeStopWordsSet = aroundPrecisionSet = aroundRadiusSet = NO; 67 | _page = 0; 68 | _attributesToHighlight = nil; 69 | _disableTypoToleranceOnAttributes = nil; 70 | _attributesToRetrieve = nil; 71 | _attributesToSnippet = nil; 72 | _tagFilters = nil; 73 | _numericFilters = nil; 74 | _fullTextQuery = pfullTextQuery; 75 | _queryType = nil; 76 | _similarQuery = nil; 77 | _removeWordsIfNoResult = nil; 78 | _typoTolerance = nil; 79 | _insideBoundingBox = nil; 80 | _insidePolygon = nil; 81 | _aroundLatLong = nil; 82 | _optionalWords = nil; 83 | _filters = nil; 84 | _facetFilters = nil; 85 | _facetFiltersRaw = nil; 86 | _facets = nil; 87 | _restrictSearchableAttributes = nil; 88 | _highlightPreTag = nil; 89 | _highlightPostTag = nil; 90 | _snippetEllipsisText = nil; 91 | _analyticsTags = nil; 92 | _userToken = nil; 93 | _referers = nil; 94 | } 95 | return self; 96 | } 97 | 98 | -(instancetype) copyWithZone:(NSZone*)zone { 99 | ASQuery *new = [[ASQuery alloc] init]; 100 | 101 | new->_parameters = [NSMutableDictionary dictionaryWithDictionary:self->_parameters]; 102 | if (minWordSizeForApprox1Set) 103 | new.minWordSizeForApprox1 = self.minWordSizeForApprox1; 104 | if (minWordSizeForApprox2Set) 105 | new.minWordSizeForApprox2 = self.minWordSizeForApprox2; 106 | if (getRankingInfoSet) 107 | new.getRankingInfo = self.getRankingInfo; 108 | if (ignorePluralSet) 109 | new.ignorePlural = self.ignorePlural; 110 | if (distinctSet) 111 | new.distinct = self.distinct; 112 | if (aroundRadiusSet) 113 | new.aroundRadius = self.aroundRadius; 114 | if (aroundPrecisionSet) 115 | new.aroundPrecision = self.aroundPrecision; 116 | new.page = self.page; 117 | if (hitsPerPageSet) 118 | new.hitsPerPage = self.hitsPerPage; 119 | if (minProximitySet) 120 | new.minProximity = self.minProximity; 121 | new.attributesToHighlight = [self.attributesToHighlight copyWithZone:zone]; 122 | new.disableTypoToleranceOnAttributes = [self.disableTypoToleranceOnAttributes copyWithZone:zone]; 123 | new.attributesToRetrieve = [self.attributesToRetrieve copyWithZone:zone]; 124 | new.attributesToSnippet = [self.attributesToSnippet copyWithZone:zone]; 125 | new.tagFilters = [self.tagFilters copyWithZone:zone]; 126 | new.numericFilters = [self.numericFilters copyWithZone:zone]; 127 | new.fullTextQuery = [self.fullTextQuery copyWithZone:zone]; 128 | new.queryType = [self.queryType copyWithZone:zone]; 129 | new.similarQuery = [self.similarQuery copyWithZone:zone]; 130 | new.removeWordsIfNoResult = [self.removeWordsIfNoResult copyWithZone:zone]; 131 | new.typoTolerance = [self.typoTolerance copyWithZone:zone]; 132 | if (typosOnNumericTokensSet) 133 | new.typosOnNumericTokens = self.typosOnNumericTokens; 134 | if (analyticsSet) 135 | new.analytics = self.analytics; 136 | if (synonymsSet) 137 | new.synonyms = self.synonyms; 138 | if (replaceSynonymsSet) 139 | new.replaceSynonyms = self.replaceSynonyms; 140 | if (optionalWordsMinimumMatchedSet) 141 | new.optionalWordsMinimumMatched = self.optionalWordsMinimumMatched; 142 | new.insideBoundingBox = [self.insideBoundingBox copyWithZone:zone]; 143 | new.insidePolygon = [self.insidePolygon copyWithZone:zone]; 144 | new.aroundLatLong = [self.aroundLatLong copyWithZone:zone]; 145 | if (aroundPrecisionSet) 146 | new.aroundLatLongViaIP = self.aroundLatLongViaIP; 147 | new.optionalWords = [self.optionalWords copyWithZone:zone]; 148 | new.filters = [self.filters copyWithZone:zone]; 149 | new.facetFilters = [self.facetFilters copyWithZone:zone]; 150 | new.facetFiltersRaw = [self.facetFiltersRaw copyWithZone:zone]; 151 | new.facets = [self.facets copyWithZone:zone]; 152 | new.restrictSearchableAttributes = [self.restrictSearchableAttributes copyWithZone:zone]; 153 | new.highlightPreTag = [self.highlightPreTag copyWithZone:zone]; 154 | new.highlightPostTag = [self.highlightPostTag copyWithZone:zone]; 155 | new.snippetEllipsisText = [self.snippetEllipsisText copyWithZone:zone]; 156 | new.analyticsTags = [self.analyticsTags copyWithZone:zone]; 157 | if (advancedSyntaxSet) 158 | new.advancedSyntax = self.advancedSyntax; 159 | if (removeStopWordsSet) 160 | new.removeStopWords = self.removeStopWords; 161 | new.userToken = self.userToken; 162 | new.referers = self.referers; 163 | if (maxValuesPerFacetSet) 164 | new.maxValuesPerFacet = self.maxValuesPerFacet; 165 | 166 | return new; 167 | } 168 | 169 | -(ASQuery*) searchAroundLatitude:(float)latitude longitude:(float)longitude 170 | { 171 | self.aroundLatLong = [NSString stringWithFormat:@"aroundLatLng=%f,%f", latitude, longitude]; 172 | return self; 173 | } 174 | 175 | -(ASQuery*) searchAroundLatitude:(float)latitude longitude:(float)longitude maxDist:(NSUInteger)maxDist 176 | { 177 | self.aroundLatLong = [NSString stringWithFormat:@"aroundLatLng=%f,%f", latitude, longitude]; 178 | self.aroundRadius = maxDist; 179 | return self; 180 | } 181 | 182 | -(ASQuery*) searchAroundLatitude:(float)latitude longitude:(float)longitude maxDist:(NSUInteger)maxDist precision:(NSUInteger)precision 183 | { 184 | self.aroundLatLong = [NSString stringWithFormat:@"aroundLatLng=%f,%f", latitude, longitude]; 185 | self.aroundRadius = maxDist; 186 | self.aroundPrecision = precision; 187 | return self; 188 | } 189 | 190 | -(ASQuery*) searchAroundLatitudeLongitudeViaIP 191 | { 192 | self.aroundLatLongViaIP = YES; 193 | return self; 194 | } 195 | 196 | -(ASQuery*) searchAroundLatitudeLongitudeViaIP:(NSUInteger)maxDist 197 | { 198 | self.aroundRadius = maxDist; 199 | self.aroundLatLongViaIP = YES; 200 | return self; 201 | } 202 | 203 | -(ASQuery*) searchAroundLatitudeLongitudeViaIP:(NSUInteger)maxDist precision:(NSUInteger)precision 204 | { 205 | self.aroundRadius = maxDist; 206 | self.aroundPrecision = precision; 207 | self.aroundLatLongViaIP = YES; 208 | return self; 209 | } 210 | 211 | 212 | -(ASQuery*) searchInsideBoundingBoxWithLatitudeP1:(float)latitudeP1 longitudeP1:(float)longitudeP1 latitudeP2:(float)latitudeP2 longitudeP2:(float)longitudeP2 213 | { 214 | if (self.insideBoundingBox != nil) { 215 | self.insideBoundingBox = [NSString stringWithFormat:@"%@,%f,%f,%f,%f", self.insideBoundingBox, latitudeP1, longitudeP1, latitudeP2, longitudeP2]; 216 | } else { 217 | self.insideBoundingBox = [NSString stringWithFormat:@"insideBoundingBox=%f,%f,%f,%f", latitudeP1, longitudeP1, latitudeP2, longitudeP2]; 218 | } 219 | return self; 220 | } 221 | 222 | -(ASQuery*) addInsidePolygon:(float)latitude longitude:(float)longitude 223 | { 224 | if (self.insidePolygon != nil) { 225 | self.insidePolygon = [NSString stringWithFormat:@"%@,%f,%f", self.insidePolygon, latitude, longitude]; 226 | } else { 227 | self.insidePolygon = [NSString stringWithFormat:@"insidePolygon=%f,%f", latitude, longitude]; 228 | } 229 | return self; 230 | } 231 | 232 | -(NSString*) buildURL 233 | { 234 | NSMutableString *stringBuilder = [[NSMutableString alloc] init]; 235 | if (self.attributesToRetrieve != nil) { 236 | [stringBuilder appendString:@"attributes="]; 237 | BOOL first = YES; 238 | for (NSString* attribute in self.attributesToRetrieve) { 239 | if (!first) 240 | [stringBuilder appendString:@","]; 241 | [stringBuilder appendString:[ASAPIClient urlEncode:attribute]]; 242 | first = NO; 243 | } 244 | } 245 | if (self.attributesToHighlight != nil) { 246 | if ([stringBuilder length] > 0) 247 | [stringBuilder appendString:@"&"]; 248 | [stringBuilder appendString:@"attributesToHighlight="]; 249 | BOOL first = YES; 250 | for (NSString* attribute in self.attributesToHighlight) { 251 | if (!first) 252 | [stringBuilder appendString:@","]; 253 | [stringBuilder appendString:[ASAPIClient urlEncode:attribute]]; 254 | first = NO; 255 | } 256 | } 257 | if (self.disableTypoToleranceOnAttributes != nil) { 258 | if ([stringBuilder length] > 0) 259 | [stringBuilder appendString:@"&"]; 260 | [stringBuilder appendString:@"disableTypoToleranceOnAttributes="]; 261 | BOOL first = YES; 262 | for (NSString* attribute in self.disableTypoToleranceOnAttributes) { 263 | if (!first) 264 | [stringBuilder appendString:@","]; 265 | [stringBuilder appendString:[ASAPIClient urlEncode:attribute]]; 266 | first = NO; 267 | } 268 | } 269 | if (self.attributesToSnippet != nil) { 270 | if ([stringBuilder length] > 0) 271 | [stringBuilder appendString:@"&"]; 272 | [stringBuilder appendString:@"attributesToSnippet="]; 273 | BOOL first = YES; 274 | for (NSString* attribute in self.attributesToSnippet) { 275 | if (!first) 276 | [stringBuilder appendString:@","]; 277 | [stringBuilder appendString:[ASAPIClient urlEncode:attribute]]; 278 | first = NO; 279 | } 280 | } 281 | if (self.filters != nil) { 282 | if ([stringBuilder length] > 0) 283 | [stringBuilder appendString:@"&"]; 284 | [stringBuilder appendString:@"filters="]; 285 | [stringBuilder appendString:[ASAPIClient urlEncode:self.filters]]; 286 | } 287 | if (self.facetFilters != nil) { 288 | if ([stringBuilder length] > 0) 289 | [stringBuilder appendString:@"&"]; 290 | [stringBuilder appendString:@"facetFilters="]; 291 | NSError* err = nil; 292 | NSData *data = [NSJSONSerialization dataWithJSONObject:self.facetFilters options:NSJSONWritingPrettyPrinted error:&err]; 293 | if (err == nil) { 294 | NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 295 | [stringBuilder appendString:[ASAPIClient urlEncode:jsonString]]; 296 | } else { 297 | @throw [NSException exceptionWithName:@"InvalidArgument" reason:@"Invalid facetFilters (should be an array of string)" userInfo:nil]; 298 | } 299 | } else if (self.facetFiltersRaw != nil) { 300 | if ([stringBuilder length] > 0) 301 | [stringBuilder appendString:@"&"]; 302 | [stringBuilder appendString:@"facetFilters="]; 303 | [stringBuilder appendString:[ASAPIClient urlEncode:self.facetFiltersRaw]]; 304 | } 305 | 306 | if (self.facets != nil) { 307 | if ([stringBuilder length] > 0) 308 | [stringBuilder appendString:@"&"]; 309 | [stringBuilder appendString:@"facets="]; 310 | BOOL first = YES; 311 | for (NSString* attribute in self.facets) { 312 | if (!first) 313 | [stringBuilder appendString:@","]; 314 | [stringBuilder appendString:[ASAPIClient urlEncode:attribute]]; 315 | first = NO; 316 | } 317 | } 318 | if (self.optionalWords != nil) { 319 | if ([stringBuilder length] > 0) 320 | [stringBuilder appendString:@"&"]; 321 | [stringBuilder appendString:@"optionalWords="]; 322 | BOOL first = YES; 323 | for (NSString* word in self.optionalWords) { 324 | if (!first) 325 | [stringBuilder appendString:@","]; 326 | [stringBuilder appendString:[ASAPIClient urlEncode:word]]; 327 | first = NO; 328 | } 329 | } 330 | if (optionalWordsMinimumMatchedSet) { 331 | if ([stringBuilder length] > 0) 332 | [stringBuilder appendString:@"&"]; 333 | [stringBuilder appendFormat:@"optionalWordsMinimumMatched=%zd", self.optionalWordsMinimumMatched]; 334 | } 335 | if (minWordSizeForApprox1Set) { 336 | if ([stringBuilder length] > 0) 337 | [stringBuilder appendString:@"&"]; 338 | [stringBuilder appendFormat:@"minWordSizefor1Typo=%zd", self.minWordSizeForApprox1]; 339 | } 340 | if (minWordSizeForApprox2Set) { 341 | if ([stringBuilder length] > 0) 342 | [stringBuilder appendString:@"&"]; 343 | [stringBuilder appendFormat:@"minWordSizefor2Typos=%zd", self.minWordSizeForApprox2]; 344 | } 345 | if (ignorePluralSet) { 346 | if ([stringBuilder length] > 0) 347 | [stringBuilder appendString:@"&"]; 348 | [stringBuilder appendFormat:@"ignorePlural=%d", self.ignorePlural]; 349 | } 350 | if (getRankingInfoSet) { 351 | if ([stringBuilder length] > 0) 352 | [stringBuilder appendString:@"&"]; 353 | [stringBuilder appendFormat:@"getRankingInfo=%d", self.getRankingInfo]; 354 | } 355 | if (typosOnNumericTokensSet) { 356 | if ([stringBuilder length] > 0) 357 | [stringBuilder appendString:@"&"]; 358 | [stringBuilder appendFormat:@"allowTyposOnNumericTokens=%d", self.typosOnNumericTokens]; 359 | } 360 | if (self.typoTolerance != nil) { 361 | if ([stringBuilder length] > 0) 362 | [stringBuilder appendString:@"&"]; 363 | [stringBuilder appendString:@"typoTolerance="]; 364 | [stringBuilder appendString:self.typoTolerance]; 365 | } 366 | if (aroundRadiusSet) { 367 | if ([stringBuilder length] > 0) 368 | [stringBuilder appendString:@"&"]; 369 | 370 | [stringBuilder appendFormat:@"aroundRadius=%zd", self.aroundRadius]; 371 | } 372 | if (aroundPrecisionSet) { 373 | if ([stringBuilder length] > 0) 374 | [stringBuilder appendString:@"&"]; 375 | 376 | [stringBuilder appendFormat:@"aroundPrecision=%zd", self.aroundPrecision]; 377 | } 378 | if (distinctSet) { 379 | if ([stringBuilder length] > 0) 380 | [stringBuilder appendString:@"&"]; 381 | 382 | [stringBuilder appendFormat:@"distinct=%zd", self.distinct]; 383 | } 384 | if (analyticsSet) { 385 | if ([stringBuilder length] > 0) 386 | [stringBuilder appendString:@"&"]; 387 | [stringBuilder appendFormat:@"analytics=%d", self.analytics]; 388 | } 389 | if (synonymsSet) { 390 | if ([stringBuilder length] > 0) 391 | [stringBuilder appendString:@"&"]; 392 | [stringBuilder appendFormat:@"synonyms=%d", self.synonyms]; 393 | } 394 | if (replaceSynonymsSet) { 395 | if ([stringBuilder length] > 0) 396 | [stringBuilder appendString:@"&"]; 397 | [stringBuilder appendFormat:@"replaceSynonymsInHighlight=%d", self.replaceSynonyms]; 398 | } 399 | if (self.page > 0) { 400 | if ([stringBuilder length] > 0) 401 | [stringBuilder appendString:@"&"]; 402 | [stringBuilder appendFormat:@"page=%zd", self.page]; 403 | } 404 | if (hitsPerPageSet) { 405 | if ([stringBuilder length] > 0) 406 | [stringBuilder appendString:@"&"]; 407 | [stringBuilder appendFormat:@"hitsPerPage=%zd", self.hitsPerPage]; 408 | } 409 | if (minProximitySet) { 410 | if ([stringBuilder length] > 0) 411 | [stringBuilder appendString:@"&"]; 412 | [stringBuilder appendFormat:@"minProximity=%zd", self.minProximity]; 413 | } 414 | if (self.queryType != nil) { 415 | if ([stringBuilder length] > 0) 416 | [stringBuilder appendString:@"&"]; 417 | [stringBuilder appendFormat:@"queryType=%@", [ASAPIClient urlEncode:self.queryType]]; 418 | } 419 | if (self.similarQuery != nil) { 420 | if ([stringBuilder length] > 0) 421 | [stringBuilder appendString:@"&"]; 422 | [stringBuilder appendFormat:@"similarQuery=%@", [ASAPIClient urlEncode:self.similarQuery]]; 423 | } 424 | if (self.removeWordsIfNoResult != nil) { 425 | if ([stringBuilder length] > 0) 426 | [stringBuilder appendString:@"&"]; 427 | [stringBuilder appendFormat:@"removeWordsIfNoResult=%@", [ASAPIClient urlEncode:self.removeWordsIfNoResult]]; 428 | } 429 | if (self.tagFilters != nil) { 430 | if ([stringBuilder length] > 0) 431 | [stringBuilder appendString:@"&"]; 432 | [stringBuilder appendFormat:@"tagFilters=%@", [ASAPIClient urlEncode:self.tagFilters]]; 433 | } 434 | if (self.numericFilters != nil) { 435 | if ([stringBuilder length] > 0) 436 | [stringBuilder appendString:@"&"]; 437 | [stringBuilder appendFormat:@"numericFilters=%@", [ASAPIClient urlEncode:self.numericFilters]]; 438 | } 439 | if (self.insideBoundingBox != nil) { 440 | if ([stringBuilder length] > 0) 441 | [stringBuilder appendString:@"&"]; 442 | [stringBuilder appendString:self.insideBoundingBox]; 443 | } else if (self.aroundLatLong != nil) { 444 | if ([stringBuilder length] > 0) 445 | [stringBuilder appendString:@"&"]; 446 | [stringBuilder appendString:self.aroundLatLong]; 447 | } else if (self.insidePolygon != nil) { 448 | if ([stringBuilder length] > 0) 449 | [stringBuilder appendString:@"&"]; 450 | [stringBuilder appendString:self.insidePolygon]; 451 | } 452 | if (aroundLatLongViaIPSet) { 453 | if ([stringBuilder length] > 0) 454 | [stringBuilder appendString:@"&"]; 455 | [stringBuilder appendFormat:@"aroundLatLngViaIP=%d", self.aroundLatLongViaIP]; 456 | } 457 | if (self.fullTextQuery != nil) { 458 | if ([stringBuilder length] > 0) 459 | [stringBuilder appendString:@"&"]; 460 | [stringBuilder appendFormat:@"query=%@", [ASAPIClient urlEncode:self.fullTextQuery]]; 461 | } 462 | if (self.restrictSearchableAttributes != nil) { 463 | if ([stringBuilder length] > 0) 464 | [stringBuilder appendString:@"&"]; 465 | [stringBuilder appendFormat:@"restrictSearchableAttributes=%@", [ASAPIClient urlEncode:self.restrictSearchableAttributes]]; 466 | } 467 | if (self.highlightPreTag != nil) { 468 | if ([stringBuilder length] > 0) 469 | [stringBuilder appendString:@"&"]; 470 | [stringBuilder appendFormat:@"highlightPreTag=%@", [ASAPIClient urlEncode:self.highlightPreTag]]; 471 | } 472 | if (self.highlightPostTag != nil) { 473 | if ([stringBuilder length] > 0) 474 | [stringBuilder appendString:@"&"]; 475 | [stringBuilder appendFormat:@"highlightPostTag=%@", [ASAPIClient urlEncode:self.highlightPostTag]]; 476 | } 477 | if (self.snippetEllipsisText != nil) { 478 | if ([stringBuilder length] > 0) 479 | [stringBuilder appendString:@"&"]; 480 | [stringBuilder appendFormat:@"snippetEllipsisText=%@", [ASAPIClient urlEncode:self.snippetEllipsisText]]; 481 | } 482 | if (self.analyticsTags != nil) { 483 | if ([stringBuilder length] > 0) 484 | [stringBuilder appendString:@"&"]; 485 | [stringBuilder appendString:@"analyticsTags="]; 486 | BOOL first = YES; 487 | for (NSString* tag in self.analyticsTags) { 488 | if (!first) 489 | [stringBuilder appendString:@","]; 490 | [stringBuilder appendString:[ASAPIClient urlEncode:tag]]; 491 | first = NO; 492 | } 493 | } 494 | if (advancedSyntaxSet) { 495 | if ([stringBuilder length] > 0) 496 | [stringBuilder appendString:@"&"]; 497 | [stringBuilder appendFormat:@"advancedSyntax=%d", self.advancedSyntax]; 498 | } 499 | if (removeStopWordsSet) { 500 | if ([stringBuilder length] > 0) 501 | [stringBuilder appendString:@"&"]; 502 | [stringBuilder appendFormat:@"removeStopWords=%d", self.removeStopWords]; 503 | } 504 | if (self.userToken != nil) { 505 | if ([stringBuilder length] > 0) 506 | [stringBuilder appendString:@"&"]; 507 | [stringBuilder appendFormat:@"userToken=%@", [ASAPIClient urlEncode:self.userToken]]; 508 | } 509 | if (self.referers != nil) { 510 | if ([stringBuilder length] > 0) 511 | [stringBuilder appendString:@"&"]; 512 | [stringBuilder appendFormat:@"referer=%@", [ASAPIClient urlEncode:self.referers]]; 513 | } 514 | if (maxValuesPerFacetSet) { 515 | if ([stringBuilder length] > 0) 516 | [stringBuilder appendString:@"&"]; 517 | [stringBuilder appendFormat:@"maxValuesPerFacet=%zd", self.maxValuesPerFacet]; 518 | } 519 | // WARNING: Any extra parameter will override any previous one with the same name. 520 | for (NSString* name in _parameters) { 521 | if ([stringBuilder length] > 0) 522 | [stringBuilder appendString:@"&"]; 523 | [stringBuilder appendString:[ASAPIClient urlEncode:name]]; 524 | [stringBuilder appendString:@"="]; 525 | [stringBuilder appendString:[ASAPIClient urlEncode:[_parameters objectForKey:name]]]; 526 | } 527 | 528 | return stringBuilder; 529 | } 530 | 531 | - (void)set:(NSString * _Nonnull)name value:(NSString * _Nullable)value { 532 | if (value == nil) { 533 | [_parameters removeObjectForKey:name]; 534 | } else { 535 | [_parameters setObject:value forKey:name]; 536 | } 537 | } 538 | 539 | - (NSString * _Nullable)get:(NSString * _Nonnull)name { 540 | return [_parameters objectForKey:name]; 541 | } 542 | 543 | - (void)setObject:(NSString * _Nullable)newValue forKeyedSubscript:(NSString * _Nonnull)index { 544 | [self set:index value:newValue]; 545 | } 546 | 547 | - (NSString * _Nullable)objectForKeyedSubscript:(NSString * _Nonnull)index { 548 | return [self get:index]; 549 | } 550 | 551 | @synthesize minWordSizeForApprox1 = _minWordSizeForApprox1; 552 | -(void) setMinWordSizeForApprox1:(NSUInteger)minWordSizeForApprox1 { 553 | _minWordSizeForApprox1 = minWordSizeForApprox1; 554 | minWordSizeForApprox1Set = true; 555 | } 556 | 557 | -(NSUInteger)minWordSizeForApprox1 { 558 | minWordSizeForApprox1Set = true; 559 | return _minWordSizeForApprox1; 560 | } 561 | 562 | @synthesize minWordSizeForApprox2 = _minWordSizeForApprox2; 563 | -(void) setMinWordSizeForApprox2:(NSUInteger)minWordSizeForApprox2 { 564 | _minWordSizeForApprox2 = minWordSizeForApprox2; 565 | minWordSizeForApprox2Set = true; 566 | } 567 | 568 | -(NSUInteger)minWordSizeForApprox2 { 569 | minWordSizeForApprox2Set = true; 570 | return _minWordSizeForApprox2; 571 | } 572 | 573 | @synthesize hitsPerPage = _hitsPerPage; 574 | -(void) setHitsPerPage:(NSUInteger)hitsPerPage { 575 | _hitsPerPage = hitsPerPage; 576 | hitsPerPageSet = true; 577 | } 578 | 579 | -(NSUInteger)hitsPerPage { 580 | hitsPerPageSet = true; 581 | return _hitsPerPage; 582 | } 583 | 584 | @synthesize minProximity = _minProximity; 585 | -(void) setMinProximity:(NSUInteger)minProximity { 586 | _minProximity = minProximity; 587 | minProximitySet = true; 588 | } 589 | 590 | -(NSUInteger)minProximity { 591 | minProximitySet = true; 592 | return _minProximity; 593 | } 594 | 595 | @synthesize getRankingInfo = _getRankingInfo; 596 | -(void) setGetRankingInfo:(BOOL)getRankingInfo { 597 | _getRankingInfo = getRankingInfo; 598 | getRankingInfoSet = true; 599 | } 600 | 601 | -(BOOL)getRankingInfo { 602 | getRankingInfoSet = true; 603 | return _getRankingInfo; 604 | } 605 | 606 | @synthesize ignorePlural = _ignorePlural; 607 | -(void) setIgnorePlural:(BOOL)ignorePlural { 608 | _ignorePlural = ignorePlural; 609 | ignorePluralSet = true; 610 | } 611 | 612 | -(BOOL)ignorePlural { 613 | ignorePluralSet = true; 614 | return _ignorePlural; 615 | } 616 | 617 | @synthesize typosOnNumericTokens = _typosOnNumericTokens; 618 | -(void) setTyposOnNumericTokens:(BOOL)typosOnNumericTokens { 619 | _typosOnNumericTokens = typosOnNumericTokens; 620 | typosOnNumericTokensSet = true; 621 | } 622 | 623 | -(BOOL)typosOnNumericTokens { 624 | typosOnNumericTokensSet = true; 625 | return _typosOnNumericTokens; 626 | } 627 | 628 | @synthesize analytics = _analytics; 629 | -(void) setAnalytics:(BOOL)analytics { 630 | _analytics = analytics; 631 | analyticsSet = true; 632 | } 633 | 634 | -(BOOL)analytics { 635 | analyticsSet = true; 636 | return _analytics; 637 | } 638 | 639 | @synthesize synonyms = _synonyms; 640 | -(void) setSynonyms:(BOOL)synonyms { 641 | _synonyms = synonyms; 642 | synonymsSet = true; 643 | } 644 | 645 | -(BOOL)synonyms { 646 | synonymsSet = true; 647 | return _synonyms; 648 | } 649 | 650 | @synthesize replaceSynonyms = _replaceSynonyms; 651 | -(void) setReplaceSynonyms:(BOOL)replaceSynonyms { 652 | _replaceSynonyms = replaceSynonyms; 653 | replaceSynonymsSet = true; 654 | } 655 | 656 | -(BOOL)replaceSynonyms { 657 | replaceSynonymsSet = true; 658 | return _replaceSynonyms; 659 | } 660 | 661 | @synthesize distinct = _distinct; 662 | -(void) setDistinct:(NSUInteger)distinct { 663 | _distinct = distinct; 664 | distinctSet = true; 665 | } 666 | 667 | -(NSUInteger)distinct { 668 | distinctSet = true; 669 | return _distinct; 670 | } 671 | 672 | @synthesize optionalWordsMinimumMatched = _optionalWordsMinimumMatched; 673 | -(void)setOptionalWordsMinimumMatched:(NSUInteger)optionalWordsMinimumMatched { 674 | _optionalWordsMinimumMatched = optionalWordsMinimumMatched; 675 | optionalWordsMinimumMatchedSet = true; 676 | } 677 | 678 | -(NSUInteger)optionalWordsMinimumMatched { 679 | optionalWordsMinimumMatchedSet = true; 680 | return _optionalWordsMinimumMatched; 681 | } 682 | @synthesize aroundRadius = _aroundRadius; 683 | -(void) setAroundRadius:(NSUInteger)aroundRadius { 684 | _aroundRadius = aroundRadius; 685 | aroundRadiusSet = true; 686 | } 687 | 688 | -(NSUInteger)aroundRadius { 689 | aroundRadiusSet = true; 690 | return _aroundRadius; 691 | } 692 | 693 | @synthesize aroundPrecision = _aroundPrecision; 694 | -(void) setAroundPrecision:(NSUInteger)aroundPrecision { 695 | _aroundPrecision = aroundPrecision; 696 | aroundPrecisionSet = true; 697 | } 698 | 699 | -(NSUInteger)aroundPrecision { 700 | aroundPrecisionSet = true; 701 | return _aroundPrecision; 702 | } 703 | 704 | @synthesize aroundLatLongViaIP = _aroundLatLongViaIP; 705 | -(void) setAroundLatLongViaIP:(BOOL)aroundLatLongViaIP { 706 | _aroundLatLongViaIP = aroundLatLongViaIP; 707 | aroundLatLongViaIPSet = true; 708 | } 709 | 710 | -(BOOL)aroundLatLongViaIP { 711 | aroundLatLongViaIPSet = true; 712 | return _aroundLatLongViaIP; 713 | } 714 | 715 | @synthesize advancedSyntax = _advancedSyntax; 716 | -(void)setAdvancedSyntax:(BOOL)advancedSyntax { 717 | _advancedSyntax = advancedSyntax; 718 | advancedSyntaxSet = true; 719 | } 720 | 721 | -(BOOL)advancedSyntax { 722 | advancedSyntaxSet = true; 723 | return _advancedSyntax; 724 | } 725 | 726 | @synthesize removeStopWords = _removeStopWords; 727 | -(void) setRemoveStopWords:(BOOL)removeStopWords { 728 | _removeStopWords = removeStopWords; 729 | removeStopWordsSet = true; 730 | } 731 | 732 | -(BOOL)removeStopWords { 733 | removeStopWordsSet = true; 734 | return _removeStopWords; 735 | } 736 | 737 | @synthesize maxValuesPerFacet = _maxValuesPerFacet; 738 | -(void) setMaxValuesPerFacet:(NSUInteger)maxValuesPerFacet { 739 | _maxValuesPerFacet = maxValuesPerFacet; 740 | maxValuesPerFacetSet = true; 741 | } 742 | 743 | -(NSUInteger)maxValuesPerFacet { 744 | maxValuesPerFacetSet = true; 745 | return _maxValuesPerFacet; 746 | } 747 | 748 | @end 749 | -------------------------------------------------------------------------------- /src/ASRemoteIndex.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2013 Algolia 3 | // http://www.algolia.com/ 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 13 | // all 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 21 | // THE SOFTWARE. 22 | // 23 | 24 | #import 25 | #import "ASQuery.h" 26 | #import "ASBrowseIterator.h" 27 | 28 | @class AFHTTPRequestOperation; 29 | @class ASAPIClient; 30 | 31 | /** 32 | * Contains all the functions related to one index 33 | * You can use APIClient.getIndex(indexName) to retrieve this object 34 | */ 35 | @interface ASRemoteIndex : NSObject 36 | 37 | /** 38 | * Index initialization 39 | */ 40 | +(instancetype) remoteIndexWithAPIClient:(ASAPIClient*)client indexName:(NSString*)indexName; 41 | 42 | /** 43 | * Index initialization 44 | */ 45 | -(instancetype) initWithAPIClient:(ASAPIClient*)client indexName:(NSString*)indexName; 46 | 47 | 48 | /** 49 | * Add an object in this index 50 | * 51 | * @param content contains the object to add inside the index. 52 | * The object is represented by an associative array 53 | */ 54 | -(AFHTTPRequestOperation *) addObject:(NSDictionary*)object 55 | success:(void(^)(ASRemoteIndex *index, NSDictionary *object, NSDictionary *result))success 56 | failure:(void(^)(ASRemoteIndex *index, NSDictionary *object, NSString *errorMessage))failure; 57 | 58 | /** 59 | * Add an object in this index 60 | * 61 | * @param content contains the object to add inside the index. 62 | * The object is represented by an associative array 63 | * @param objectID an objectID you want to attribute to this object 64 | * (if the attribute already exist the old object will be overwrite) 65 | */ 66 | -(AFHTTPRequestOperation *) addObject:(NSDictionary*)object 67 | withObjectID:(NSString*)objectID 68 | success:(void(^)(ASRemoteIndex *index, NSDictionary *object, NSString *objectID, NSDictionary *result))success 69 | failure:(void(^)(ASRemoteIndex *index, NSDictionary *object, NSString *objectID, NSString *errorMessage))failure; 70 | 71 | /** 72 | * Add several objects 73 | * 74 | * @param objects contains an array of objects to add (NSArray of NSDictionary object). 75 | */ 76 | -(AFHTTPRequestOperation *) addObjects:(NSArray*)objects 77 | success:(void(^)(ASRemoteIndex *index, NSArray *objects, NSDictionary *result))success 78 | failure:(void(^)(ASRemoteIndex *index, NSArray *objects, NSString *errorMessage))failure; 79 | 80 | /** 81 | * Delete several objects 82 | * 83 | * @param objects contains an array of objectID to delete (NSArray of NSString object). 84 | */ 85 | -(AFHTTPRequestOperation *) deleteObjects:(NSArray*)objects 86 | success:(void(^)(ASRemoteIndex *index, NSArray *objects, NSDictionary *result))success 87 | failure:(void(^)(ASRemoteIndex *index, NSArray *objects, NSString *errorMessage))failure; 88 | 89 | /** 90 | * Get an object from this index 91 | * 92 | * @param objectID the unique identifier of the object to retrieve 93 | */ 94 | -(AFHTTPRequestOperation *) getObject:(NSString*)objectID 95 | success:(void(^)(ASRemoteIndex *index, NSString *objectID, NSDictionary *result))success 96 | failure:(void(^)(ASRemoteIndex *index, NSString *objectID, NSString *errorMessage))failure; 97 | 98 | /** 99 | * Get an object from this index 100 | * 101 | * @param objectID the unique identifier of the object to retrieve 102 | * @param attributesToRetrieve, contains the list of attributes to retrieve as a string separated by "," 103 | */ 104 | -(AFHTTPRequestOperation *) getObject:(NSString*)objectID 105 | attributesToRetrieve:(NSArray*)attributes 106 | success:(void(^)(ASRemoteIndex *index, NSString *objectID, NSArray *attributesToRetrieve, NSDictionary *result))success 107 | failure:(void(^)(ASRemoteIndex *index, NSString *objectID, NSArray *attributesToRetrieve, NSString *errorMessage))failure; 108 | 109 | /** 110 | * Get several objects from this index 111 | * 112 | * @param objectIDs the array of unique identifier of objects to retrieve 113 | */ 114 | -(AFHTTPRequestOperation *) getObjects:(NSArray*)objectIDs 115 | success:(void(^)(ASRemoteIndex *index, NSArray *objectIDs, NSDictionary *result))success 116 | failure:(void(^)(ASRemoteIndex *index, NSArray *objectIDs, NSString *errorMessage))failure; 117 | 118 | /** 119 | * Update partially an object (only update attributes passed in argument) 120 | * 121 | * @param partialObject contains the object attributes to override, the 122 | * object must contains an objectID attribute 123 | */ 124 | -(AFHTTPRequestOperation *) partialUpdateObject:(NSDictionary*)partialObject 125 | objectID:(NSString*)objectID 126 | success:(void(^)(ASRemoteIndex *index, NSDictionary *partialObject, NSString *objectID, NSDictionary *result))success 127 | failure:(void(^)(ASRemoteIndex *index, NSDictionary *partialObject, NSString *objectID, NSString *errorMessage))failure; 128 | 129 | /** 130 | * Partially override the content of several objects 131 | * 132 | * @param objects contains an array of NSDictionary to update (each NSDictionary must contains an objectID attribute) 133 | */ 134 | -(AFHTTPRequestOperation *) partialUpdateObjects:(NSArray*)objects 135 | success:(void(^)(ASRemoteIndex *index, NSArray *objects, NSDictionary *result))success 136 | failure:(void(^)(ASRemoteIndex *index, NSArray *objects, NSString *errorMessage))failure; 137 | 138 | 139 | /** 140 | * Override the content of object 141 | * 142 | * @param object contains the object to save 143 | */ 144 | -(AFHTTPRequestOperation *) saveObject:(NSDictionary*)object 145 | objectID:(NSString*)objectID 146 | success:(void(^)(ASRemoteIndex *index, NSDictionary *object, NSString *objectID, NSDictionary *result))success 147 | failure:(void(^)(ASRemoteIndex *index, NSDictionary *object, NSString *objectID, NSString *errorMessage))failure; 148 | 149 | /** 150 | * Override the content of several objects 151 | * 152 | * @param objects contains an array of NSDictionary to update (each NSDictionary must contains an objectID attribute) 153 | */ 154 | -(AFHTTPRequestOperation *) saveObjects:(NSArray*)objects 155 | success:(void(^)(ASRemoteIndex *index, NSArray *objects, NSDictionary *result))success 156 | failure:(void(^)(ASRemoteIndex *index, NSArray *objects, NSString *errorMessage))failure; 157 | 158 | /** 159 | * Delete an object from the index 160 | * 161 | * @param objectID the unique identifier of object to delete 162 | */ 163 | -(AFHTTPRequestOperation *) deleteObject:(NSString*)objectID 164 | success:(void(^)(ASRemoteIndex *index, NSString *objectID, NSDictionary *result))success 165 | failure:(void(^)(ASRemoteIndex *index, NSString *objectID, NSString *errorMessage))failure; 166 | 167 | /** 168 | * Search inside the index 169 | */ 170 | -(AFHTTPRequestOperation *) search:(ASQuery*)query 171 | success:(void(^)(ASRemoteIndex *index, ASQuery *query, NSDictionary *result))success 172 | failure:(void(^)(ASRemoteIndex *index, ASQuery *query, NSString *errorMessage))failure; 173 | 174 | /** 175 | * Wait the publication of a task on the server. 176 | * All server task are asynchronous and you can check with this method that the task is published. 177 | * 178 | * @param taskID the id of the task returned by server 179 | */ 180 | -(AFHTTPRequestOperation *) waitTask:(NSString*)taskID 181 | success:(void(^)(ASRemoteIndex *index, NSString *taskID, NSDictionary *result))success 182 | failure:(void(^)(ASRemoteIndex *index, NSString *taskID, NSString *errorMessage))failure; 183 | 184 | 185 | /** 186 | * Get settings of this index 187 | */ 188 | -(AFHTTPRequestOperation *) getSettings:(void(^)(ASRemoteIndex *index, NSDictionary *result))success 189 | failure:(void(^)(ASRemoteIndex *index, NSString *errorMessage))failure; 190 | 191 | /** 192 | * Set settings for this index 193 | * 194 | * @param settigns the settings object that can contains : 195 | * - minWordSizefor1Typo: (integer) the minimum number of characters to accept one typo (default = 3). 196 | * - minWordSizefor2Typos: (integer) the minimum number of characters to accept two typos (default = 7). 197 | * - hitsPerPage: (integer) the number of hits per page (default = 10). 198 | * - attributesToRetrieve: (array of strings) default list of attributes to retrieve in objects. 199 | * If set to null, all attributes are retrieved. 200 | * - attributesToHighlight: (array of strings) default list of attributes to highlight. 201 | * If set to null, all indexed attributes are highlighted. 202 | * - attributesToSnippet**: (array of strings) default list of attributes to snippet alongside the number of words to return (syntax is attributeName:nbWords). 203 | * By default no snippet is computed. If set to null, no snippet is computed. 204 | * - attributesToIndex: (array of strings) the list of fields you want to index. 205 | * If set to null, all textual and numerical attributes of your objects are indexed, but you should update it to get optimal results. 206 | * This parameter has two important uses: 207 | * - Limit the attributes to index: For example if you store a binary image in base64, you want to store it and be able to 208 | * retrieve it but you don't want to search in the base64 string. 209 | * - Control part of the ranking*: (see the ranking parameter for full explanation) Matches in attributes at the beginning of 210 | * the list will be considered more important than matches in attributes further down the list. 211 | * In one attribute, matching text at the beginning of the attribute will be considered more important than text after, you can disable 212 | * this behavior if you add your attribute inside `unordered(AttributeName)`, for example attributesToIndex: ["title", "unordered(text)"]. 213 | * - attributesForFaceting: (array of strings) The list of fields you want to use for faceting. 214 | * All strings in the attribute selected for faceting are extracted and added as a facet. If set to null, no attribute is used for faceting. 215 | * - ranking: (array of strings) controls the way results are sorted. 216 | * We have six available criteria: 217 | * - typo: sort according to number of typos, 218 | * - geo: sort according to decreassing distance when performing a geo-location based search, 219 | * - proximity: sort according to the proximity of query words in hits, 220 | * - attribute: sort according to the order of attributes defined by attributesToIndex, 221 | * - exact: sort according to the number of words that are matched identical to query word (and not as a prefix), 222 | * - custom: sort according to a user defined formula set in **customRanking** attribute. 223 | * The standard order is ["typo", "geo", "proximity", "attribute", "exact", "custom"] 224 | * - customRanking: (array of strings) lets you specify part of the ranking. 225 | * The syntax of this condition is an array of strings containing attributes prefixed by asc (ascending order) or desc (descending order) operator. 226 | * For example `"customRanking" => ["desc(population)", "asc(name)"]` 227 | * - queryType: Select how the query words are interpreted, it can be one of the following value: 228 | * - prefixAll: all query words are interpreted as prefixes, 229 | * - prefixLast: only the last word is interpreted as a prefix (default behavior), 230 | * - prefixNone: no query word is interpreted as a prefix. This option is not recommended. 231 | * - highlightPreTag: (string) Specify the string that is inserted before the highlighted parts in the query result (default to ""). 232 | * - highlightPostTag: (string) Specify the string that is inserted after the highlighted parts in the query result (default to ""). 233 | * - optionalWords: (array of strings) Specify a list of words that should be considered as optional when found in the query. 234 | */ 235 | -(AFHTTPRequestOperation *) setSettings:(NSDictionary*)settings 236 | success:(void(^)(ASRemoteIndex *index, NSDictionary *settings, NSDictionary *result))success 237 | failure:(void(^)(ASRemoteIndex *index, NSDictionary *settings, NSString *errorMessage))failure; 238 | 239 | /** 240 | * Delete the index content without removing settings and index specific API keys. 241 | */ 242 | -(AFHTTPRequestOperation *) clearIndex:(void(^)(ASRemoteIndex *index, NSDictionary *result))success 243 | failure:(void(^)(ASRemoteIndex *index, NSString *errorMessage))failure; 244 | 245 | /** 246 | * List all existing user keys associated to this index 247 | */ 248 | -(AFHTTPRequestOperation *) listUserKeys:(void(^)(ASRemoteIndex *index, NSDictionary *result))success 249 | failure:(void(^)(ASRemoteIndex *index, NSString *errorMessage))failure; 250 | 251 | /** 252 | * Get ACL of a user key associated to this index 253 | */ 254 | -(AFHTTPRequestOperation *) getUserKeyACL:(NSString*)key 255 | success:(void(^)(ASRemoteIndex *index, NSString *key, NSDictionary *result))success 256 | failure:(void(^)(ASRemoteIndex *index, NSString *key, NSString *errorMessage))failure; 257 | 258 | /** 259 | * Delete an existing user key associated to this index 260 | */ 261 | -(AFHTTPRequestOperation *) deleteUserKey:(NSString*)key 262 | success:(void(^)(ASRemoteIndex *index, NSString *key, NSDictionary *result))success 263 | failure:(void(^)(ASRemoteIndex *index, NSString *key, NSString *errorMessage))failure; 264 | 265 | /** 266 | * Create a new user key associated to this index 267 | * 268 | * @param acls the list of ACL for this key. Defined by an array of NSString that 269 | * can contains the following values: 270 | * - search: allow to search (https and http) 271 | * - addObject: allows to add/update an object in the index (https only) 272 | * - deleteObject : allows to delete an existing object (https only) 273 | * - deleteIndex : allows to delete index content (https only) 274 | * - settings : allows to get index settings (https only) 275 | * - editSettings : allows to change index settings (https only) 276 | */ 277 | -(AFHTTPRequestOperation *) addUserKey:(NSArray*)acls 278 | success:(void(^)(ASRemoteIndex *index, NSArray *acls, NSDictionary *result))success 279 | failure:(void(^)(ASRemoteIndex *index, NSArray *acls, NSString *errorMessage))failure; 280 | 281 | /** 282 | * Create a new user key associated to this index 283 | * 284 | * @param acls the list of ACL for this key. Defined by an array of NSString that 285 | * can contains the following values: 286 | * - search: allow to search (https and http) 287 | * - addObject: allows to add/update an object in the index (https only) 288 | * - deleteObject : allows to delete an existing object (https only) 289 | * - deleteIndex : allows to delete index content (https only) 290 | * - settings : allows to get index settings (https only) 291 | * - editSettings : allows to change index settings (https only) 292 | * @param params The list of parameters for this key. Defined by a NSDictionary that 293 | * can contains the following values: 294 | * - acl: array of string 295 | * - indices: array of string 296 | * - validity: int 297 | * - referers: array of string 298 | * - description: string 299 | * - maxHitsPerQuery: integer 300 | * - queryParameters: string 301 | * - maxQueriesPerIPPerHour: integer 302 | */ 303 | -(AFHTTPRequestOperation *) addUserKey:(NSArray*)acls 304 | withParams:(NSDictionary*)params 305 | success:(void(^)(ASRemoteIndex *index, NSArray* acls, NSDictionary *params, NSDictionary *result))success 306 | failure:(void(^)(ASRemoteIndex *index, NSArray* acls, NSDictionary *params, NSString *errorMessage))failure; 307 | 308 | 309 | /** 310 | * Create a new user key associated to this index 311 | * 312 | * @param acls the list of ACL for this key. Defined by an array of NSString that 313 | * can contains the following values: 314 | * - search: allow to search (https and http) 315 | * - addObject: allows to add/update an object in the index (https only) 316 | * - deleteObject : allows to delete an existing object (https only) 317 | * - deleteIndex : allows to delete index content (https only) 318 | * - settings : allows to get index settings (https only) 319 | * - editSettings : allows to change index settings (https only) 320 | * @param validity the number of seconds after which the key will be automatically removed (0 means no time limit for this key) 321 | * @param maxQueriesPerIPPerHour Specify the maximum number of API calls allowed from an IP address per hour. Defaults to 0 (no rate limit). 322 | * @param maxHitsPerQuery Specify the maximum number of hits this API key can retrieve in one call. Defaults to 0 (unlimited) 323 | */ 324 | -(AFHTTPRequestOperation *) addUserKey:(NSArray*)acls 325 | withValidity:(NSUInteger)validity 326 | maxQueriesPerIPPerHour:(NSUInteger)maxQueriesPerIPPerHour 327 | maxHitsPerQuery:(NSUInteger)maxHitsPerQuery 328 | success:(void(^)(ASRemoteIndex *index, NSArray *acls, NSDictionary *result))success 329 | failure:(void(^)(ASRemoteIndex *index, NSArray *acls, NSString *errorMessage))failure; 330 | 331 | /** 332 | * Update a user key associated to this index 333 | * 334 | * @params params the list of parameters for this key. Defined by a NSDictionary that 335 | * can contains the following values: 336 | * - acl: array of string 337 | * - indices: array of string 338 | * - validity: int 339 | * - referers: array of string 340 | * - description: string 341 | * - maxHitsPerQuery: integer 342 | * - queryParameters: string 343 | * - maxQueriesPerIPPerHour: integer 344 | */ 345 | -(AFHTTPRequestOperation *) updateUserKey:(NSString*)key 346 | withParams:(NSDictionary*)params 347 | success:(void(^)(ASRemoteIndex *index, NSString *key, NSDictionary *params, NSDictionary *result))success 348 | failure:(void(^)(ASRemoteIndex *index, NSString *key, NSDictionary *params, NSString *errorMessage))failure; 349 | 350 | /** 351 | * Update a user key associated to this index 352 | * 353 | * @param acls the list of ACL for this key. Defined by an array of NSString that 354 | * can contains the following values: 355 | * - search: allow to search (https and http) 356 | * - addObject: allows to add/update an object in the index (https only) 357 | * - deleteObject : allows to delete an existing object (https only) 358 | * - deleteIndex : allows to delete index content (https only) 359 | * - settings : allows to get index settings (https only) 360 | * - editSettings : allows to change index settings (https only) 361 | */ 362 | -(AFHTTPRequestOperation *) updateUserKey:(NSString*)key 363 | withACL:(NSArray*)acls 364 | success:(void(^)(ASRemoteIndex *index, NSString *key, NSArray *acls, NSDictionary *result))success 365 | failure:(void(^)(ASRemoteIndex *index, NSString *key, NSArray *acls, NSString *errorMessage))failure; 366 | 367 | /** 368 | * Update a new user key associated to this index 369 | * 370 | * @param acls the list of ACL for this key. Defined by an array of NSString that 371 | * can contains the following values: 372 | * - search: allow to search (https and http) 373 | * - addObject: allows to add/update an object in the index (https only) 374 | * - deleteObject : allows to delete an existing object (https only) 375 | * - deleteIndex : allows to delete index content (https only) 376 | * - settings : allows to get index settings (https only) 377 | * - editSettings : allows to change index settings (https only) 378 | * @param validity the number of seconds after which the key will be automatically removed (0 means no time limit for this key) 379 | * @param maxQueriesPerIPPerHour Specify the maximum number of API calls allowed from an IP address per hour. Defaults to 0 (no rate limit). 380 | * @param maxHitsPerQuery Specify the maximum number of hits this API key can retrieve in one call. Defaults to 0 (unlimited) 381 | */ 382 | -(AFHTTPRequestOperation *) updateUserKey:(NSString*)key 383 | withACL:(NSArray*)acls 384 | withValidity:(NSUInteger)validity 385 | maxQueriesPerIPPerHour:(NSUInteger)maxQueriesPerIPPerHour 386 | maxHitsPerQuery:(NSUInteger)maxHitsPerQuery 387 | success:(void(^)(ASRemoteIndex *index, NSString *key, NSArray *acls, NSDictionary *result))success 388 | failure:(void(^)(ASRemoteIndex *index, NSString *key, NSArray *acls, NSString *errorMessage))failure; 389 | 390 | /** 391 | * Browse all index content 392 | * 393 | * @param page Pagination parameter used to select the page to retrieve. 394 | * Page is zero-based and defaults to 0. Thus, to retrieve the 10th page you need to set page=9 395 | * @param hitsPerPage: Pagination parameter used to select the number of hits per page. Defaults to 1000. 396 | */ 397 | -(AFHTTPRequestOperation *) browse:(NSUInteger)page 398 | hitsPerPage:(NSUInteger)hitsPerPage 399 | success:(void(^)(ASRemoteIndex *index, NSUInteger page, NSUInteger hitsPerPage, NSDictionary *result))success 400 | failure:(void(^)(ASRemoteIndex *index, NSUInteger page, NSUInteger hitsPerPage, NSString *errorMessage))failure; 401 | 402 | /** 403 | * Browse all index content 404 | * 405 | * @param page Pagination parameter used to select the page to retrieve. 406 | * Page is zero-based and defaults to 0. Thus, to retrieve the 10th page you need to set page=9 407 | */ 408 | -(AFHTTPRequestOperation *) browse:(NSUInteger)page 409 | success:(void(^)(ASRemoteIndex *index, NSUInteger page, NSDictionary *result))success 410 | failure:(void(^)(ASRemoteIndex *index, NSUInteger page, NSString *errorMessage))failure; 411 | 412 | /** 413 | * Browse all index content. 414 | * 415 | * The iterator object has a attribute `result` that contains the result of the current page. 416 | * At the end of the block handler, call the method `next` of the iterator object to get the next page. 417 | * The attribute `end` is set to true when all the index was browsed. 418 | * 419 | * @param query The query parameters for the browse. 420 | */ 421 | -(void) browseWithQuery:(ASQuery*)query block:(BrowseIteratorHandler)block; 422 | 423 | /** 424 | * Browse the index from a cursor. 425 | * 426 | * The iterator object has a attribute `result` that contains the result of the current page. 427 | * At the end of the block handler, call the method `next` of the iterator object to get the next page. 428 | * The attribute `end` is set to true when all the index was browsed. 429 | * 430 | * @param cursor The cursor of the next page to retrieve. 431 | */ 432 | -(void) browseFromCursor:(NSString*)cursor block:(BrowseIteratorHandler)block; 433 | 434 | /** 435 | * Delete all previous search queries 436 | */ 437 | -(void) cancelPreviousSearches; 438 | 439 | /** 440 | * Enable search cache. 441 | */ 442 | - (void)enableSearchCache; 443 | 444 | /** 445 | * Enable search cache. 446 | * 447 | * @param eti Each cached search will be valid during this interval of time 448 | */ 449 | - (void)enableSearchCacheWithExpiringTimeInterval:(NSTimeInterval)eti; 450 | 451 | /** 452 | * Disable search cache 453 | */ 454 | - (void)disableSearchCache; 455 | 456 | /** 457 | * Clear search cache 458 | */ 459 | - (void)clearSearchCache; 460 | 461 | @property (nonatomic) NSString *indexName; 462 | @property (readonly, nonatomic) ASAPIClient *apiClient; 463 | @property (nonatomic) NSString *urlEncodedIndexName; 464 | 465 | @end 466 | -------------------------------------------------------------------------------- /src/ASRemoteIndex.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2013 Algolia 3 | // http://www.algolia.com/ 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 13 | // all 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 21 | // THE SOFTWARE. 22 | // 23 | 24 | #import "ASRemoteIndex.h" 25 | #import "ASAPIClient+Network.h" 26 | #import "ASExpiringCache.h" 27 | 28 | @interface ASRemoteIndex () 29 | 30 | - (AFHTTPRequestOperation*)performSearchQuery:(NSString*)path 31 | method:(NSString*)method 32 | body:(NSDictionary*)body 33 | success:(void(^)(id JSON))success 34 | failure:(void(^)(NSString *errorMessage))failure; 35 | 36 | @end 37 | 38 | @implementation ASRemoteIndex { 39 | ASExpiringCache *searchCache; 40 | } 41 | 42 | +(instancetype) remoteIndexWithAPIClient:(ASAPIClient*)client indexName:(NSString*)indexName 43 | { 44 | return [[ASRemoteIndex alloc] initWithAPIClient:client indexName:indexName]; 45 | } 46 | 47 | -(instancetype) initWithAPIClient:(ASAPIClient*)client indexName:(NSString*)indexName 48 | { 49 | self = [super init]; 50 | if (self) { 51 | _apiClient = client; 52 | _indexName = indexName; 53 | _urlEncodedIndexName = [ASAPIClient urlEncode:indexName]; 54 | 55 | searchCache = nil; 56 | } 57 | return self; 58 | } 59 | 60 | -(AFHTTPRequestOperation *) addObject:(NSDictionary*)object 61 | success:(void(^)(ASRemoteIndex *index, NSDictionary *object, NSDictionary *result))success 62 | failure:(void(^)(ASRemoteIndex *index, NSDictionary *object, NSString *errorMessage))failure 63 | { 64 | NSString *path = [NSString stringWithFormat:@"/1/indexes/%@", self.urlEncodedIndexName]; 65 | return [self.apiClient performHTTPQuery:path method:@"POST" body:object managers:self.apiClient.writeOperationManagers index:0 timeout:self.apiClient.timeout success:^(id JSON) { 66 | if (success != nil) 67 | success(self, object, JSON); 68 | } failure:^(NSString *errorMessage) { 69 | if (failure != nil) 70 | failure(self, object, errorMessage); 71 | }]; 72 | } 73 | 74 | -(AFHTTPRequestOperation *) addObject:(NSDictionary*)object 75 | withObjectID:(NSString*)objectID 76 | success:(void(^)(ASRemoteIndex *index, NSDictionary *object, NSString *objectID, NSDictionary *result))success 77 | failure:(void(^)(ASRemoteIndex *index, NSDictionary *object, NSString *objectID, NSString *errorMessage))failure 78 | { 79 | NSString *path = [NSString stringWithFormat:@"/1/indexes/%@/%@", self.urlEncodedIndexName, [ASAPIClient urlEncode:objectID]]; 80 | return [self.apiClient performHTTPQuery:path method:@"PUT" body:object managers:self.apiClient.writeOperationManagers index:0 timeout:self.apiClient.timeout success:^(id JSON) { 81 | if (success != nil) 82 | success(self, object, objectID, JSON); 83 | } failure:^(NSString *errorMessage) { 84 | if (failure != nil) 85 | failure(self, object, objectID, errorMessage); 86 | }]; 87 | } 88 | 89 | -(AFHTTPRequestOperation *) addObjects:(NSArray*)objects 90 | success:(void(^)(ASRemoteIndex *index, NSArray *objects, NSDictionary *result))success 91 | failure:(void(^)(ASRemoteIndex *index, NSArray *objects, NSString *errorMessage))failure 92 | { 93 | NSString *path = [NSString stringWithFormat:@"/1/indexes/%@/batch", self.urlEncodedIndexName]; 94 | NSMutableArray *requests = [[NSMutableArray alloc] initWithCapacity:[objects count]]; 95 | for (NSDictionary *object in objects) { 96 | [requests addObject:@{@"action": @"addObject", 97 | @"body": object}]; 98 | } 99 | NSDictionary *request = @{@"requests": requests}; 100 | return [self.apiClient performHTTPQuery:path method:@"POST" body:request managers:self.apiClient.writeOperationManagers index:0 timeout:self.apiClient.timeout success:^(id JSON) { 101 | if (success != nil) 102 | success(self, objects, JSON); 103 | } failure:^(NSString *errorMessage) { 104 | if (failure != nil) 105 | failure(self, objects, errorMessage); 106 | }]; 107 | } 108 | 109 | -(AFHTTPRequestOperation *) deleteObjects:(NSArray*)objects 110 | success:(void(^)(ASRemoteIndex *index, NSArray *objects, NSDictionary *result))success 111 | failure:(void(^)(ASRemoteIndex *index, NSArray *objects, NSString *errorMessage))failure 112 | { 113 | NSString *path = [NSString stringWithFormat:@"/1/indexes/%@/batch", self.urlEncodedIndexName]; 114 | NSMutableArray *requests = [[NSMutableArray alloc] initWithCapacity:[objects count]]; 115 | for (NSString *object in objects) { 116 | [requests addObject:@{@"action": @"deleteObject", 117 | @"objectID": object}]; 118 | } 119 | NSDictionary *request = @{@"requests": requests}; 120 | return [self.apiClient performHTTPQuery:path method:@"POST" body:request managers:self.apiClient.writeOperationManagers index:0 timeout:self.apiClient.timeout success:^(id JSON) { 121 | if (success != nil) 122 | success(self, objects, JSON); 123 | } failure:^(NSString *errorMessage) { 124 | if (failure != nil) 125 | failure(self, objects, errorMessage); 126 | }]; 127 | } 128 | 129 | -(AFHTTPRequestOperation *) getObject:(NSString*)objectID 130 | success:(void(^)(ASRemoteIndex *index, NSString *objectID, NSDictionary *result))success 131 | failure:(void(^)(ASRemoteIndex *index, NSString *objectID, NSString *errorMessage))failure 132 | { 133 | NSString *path = [NSString stringWithFormat:@"/1/indexes/%@/%@", self.urlEncodedIndexName, [ASAPIClient urlEncode:objectID]]; 134 | return [self.apiClient performHTTPQuery:path method:@"GET" body:nil managers:self.apiClient.searchOperationManagers index:0 timeout:self.apiClient.timeout success:^(id JSON) { 135 | if (success != nil) 136 | success(self, objectID, JSON); 137 | } failure:^(NSString *errorMessage) { 138 | if (failure != nil) 139 | failure(self, objectID, errorMessage); 140 | }]; 141 | } 142 | 143 | -(AFHTTPRequestOperation *) getObject:(NSString*)objectID 144 | attributesToRetrieve:(NSArray*)attributes 145 | success:(void(^)(ASRemoteIndex *index, NSString *objectID, NSArray *attributesToRetrieve, NSDictionary *result))success 146 | failure:(void(^)(ASRemoteIndex *index, NSString *objectID, NSArray *attributesToRetrieve, NSString *errorMessage))failure 147 | { 148 | NSMutableString *path = [NSMutableString stringWithFormat:@"/1/indexes/%@/%@?attributes=", self.urlEncodedIndexName, [ASAPIClient urlEncode:objectID]]; 149 | BOOL firstEntry = YES; 150 | for (NSString *attribute in attributes) { 151 | if (!firstEntry) 152 | [path appendString:@","]; 153 | [path appendString:[ASAPIClient urlEncode:attribute]]; 154 | firstEntry = NO; 155 | } 156 | return [self.apiClient performHTTPQuery:path method:@"GET" body:nil managers:self.apiClient.searchOperationManagers index:0 timeout:self.apiClient.timeout success:^(id JSON) { 157 | if (success != nil) 158 | success(self, objectID, attributes, JSON); 159 | } failure:^(NSString *errorMessage) { 160 | if (failure != nil) 161 | failure(self, objectID, attributes, errorMessage); 162 | }]; 163 | } 164 | 165 | -(AFHTTPRequestOperation *) getObjects:(NSArray*)objectIDs 166 | success:(void(^)(ASRemoteIndex *index, NSArray *objectIDs, NSDictionary *result))success 167 | failure:(void(^)(ASRemoteIndex *index, NSArray *objectIDs, NSString *errorMessage))failure 168 | { 169 | NSString *path = [NSString stringWithFormat:@"/1/indexes/*/objects"]; 170 | 171 | NSMutableArray *requests = [[NSMutableArray alloc] initWithCapacity:[objectIDs count]]; 172 | for (NSString *id in objectIDs) { 173 | [requests addObject:@{@"indexName": self.indexName, @"objectID": id}]; 174 | } 175 | 176 | 177 | return [self.apiClient performHTTPQuery:path method:@"POST" body:@{@"requests": requests} managers:self.apiClient.searchOperationManagers index:0 timeout:self.apiClient.timeout success:^(id JSON) { 178 | if (success != nil) 179 | success(self, objectIDs, JSON); 180 | } failure:^(NSString *errorMessage) { 181 | if (failure != nil) 182 | failure(self, objectIDs, errorMessage); 183 | }]; 184 | } 185 | 186 | -(AFHTTPRequestOperation *) partialUpdateObject:(NSDictionary*)partialObject 187 | objectID:(NSString*)objectID 188 | success:(void(^)(ASRemoteIndex *index, NSDictionary *partialObject, NSString *objectID, NSDictionary *result))success 189 | failure:(void(^)(ASRemoteIndex *index, NSDictionary *partialObject, NSString *objectID, NSString *errorMessage))failure 190 | { 191 | NSString *path = [NSString stringWithFormat:@"/1/indexes/%@/%@/partial", self.urlEncodedIndexName, [ASAPIClient urlEncode:objectID]]; 192 | return [self.apiClient performHTTPQuery:path method:@"POST" body:partialObject managers:self.apiClient.writeOperationManagers index:0 timeout:self.apiClient.timeout success:^(id JSON) { 193 | if (success != nil) 194 | success(self, partialObject, objectID, JSON); 195 | } failure:^(NSString *errorMessage) { 196 | if (failure != nil) 197 | failure(self, partialObject, objectID, errorMessage); 198 | }]; 199 | } 200 | 201 | -(AFHTTPRequestOperation *) partialUpdateObjects:(NSArray*)objects 202 | success:(void(^)(ASRemoteIndex *index, NSArray *objects, NSDictionary *result))success 203 | failure:(void(^)(ASRemoteIndex *index, NSArray *objects, NSString *errorMessage))failure 204 | { 205 | NSString *path = [NSString stringWithFormat:@"/1/indexes/%@/batch", self.urlEncodedIndexName]; 206 | NSMutableArray *requests = [[NSMutableArray alloc] initWithCapacity:[objects count]]; 207 | for (NSDictionary *object in objects) { 208 | [requests addObject:@{@"action": @"partialUpdateObject", 209 | @"objectID": [object valueForKey:@"objectID"], 210 | @"body": object}]; 211 | } 212 | NSDictionary *request = @{@"requests": requests}; 213 | return [self.apiClient performHTTPQuery:path method:@"POST" body:request managers:self.apiClient.writeOperationManagers index:0 timeout:self.apiClient.timeout success:^(id JSON) { 214 | if (success != nil) 215 | success(self, objects, JSON); 216 | } failure:^(NSString *errorMessage) { 217 | if (failure != nil) 218 | failure(self, objects, errorMessage); 219 | }]; 220 | } 221 | 222 | -(AFHTTPRequestOperation *) saveObject:(NSDictionary*)object 223 | objectID:(NSString*)objectID 224 | success:(void(^)(ASRemoteIndex *index, NSDictionary *object, NSString *objectID, NSDictionary *result))success 225 | failure:(void(^)(ASRemoteIndex *index, NSDictionary *object, NSString *objectID, NSString *errorMessage))failure 226 | { 227 | NSString *path = [NSString stringWithFormat:@"/1/indexes/%@/%@", self.urlEncodedIndexName, [ASAPIClient urlEncode:objectID]]; 228 | return [self.apiClient performHTTPQuery:path method:@"PUT" body:object managers:self.apiClient.writeOperationManagers index:0 timeout:self.apiClient.timeout success:^(id JSON) { 229 | if (success != nil) 230 | success(self, object, objectID, JSON); 231 | } failure:^(NSString *errorMessage) { 232 | if (failure != nil) 233 | failure(self, object, objectID, errorMessage); 234 | }]; 235 | } 236 | 237 | -(AFHTTPRequestOperation *) saveObjects:(NSArray*)objects 238 | success:(void(^)(ASRemoteIndex *index, NSArray *objects, NSDictionary *result))success 239 | failure:(void(^)(ASRemoteIndex *index, NSArray *objects, NSString *errorMessage))failure 240 | { 241 | NSString *path = [NSString stringWithFormat:@"/1/indexes/%@/batch", self.urlEncodedIndexName]; 242 | NSMutableArray *requests = [[NSMutableArray alloc] initWithCapacity:[objects count]]; 243 | for (NSDictionary *object in objects) { 244 | [requests addObject:@{@"action": @"updateObject", 245 | @"objectID": [object valueForKey:@"objectID"], 246 | @"body": object}]; 247 | } 248 | NSDictionary *request = @{@"requests": requests}; 249 | return [self.apiClient performHTTPQuery:path method:@"POST" body:request managers:self.apiClient.writeOperationManagers index:0 timeout:self.apiClient.timeout success:^(id JSON) { 250 | if (success != nil) 251 | success(self, objects, JSON); 252 | } failure:^(NSString *errorMessage) { 253 | if (failure != nil) 254 | failure(self, objects, errorMessage); 255 | }]; 256 | } 257 | 258 | -(AFHTTPRequestOperation *) deleteObject:(NSString*)objectID 259 | success:(void(^)(ASRemoteIndex *index, NSString *objectID, NSDictionary *result))success 260 | failure:(void(^)(ASRemoteIndex *index, NSString *objectID, NSString *errorMessage))failure 261 | { 262 | NSAssert(objectID != nil && [objectID length] != 0, @"empty objectID is not allowed"); 263 | 264 | NSString *path = [NSString stringWithFormat:@"/1/indexes/%@/%@", self.urlEncodedIndexName, [ASAPIClient urlEncode:objectID]]; 265 | return [self.apiClient performHTTPQuery:path method:@"DELETE" body:nil managers:self.apiClient.writeOperationManagers index:0 timeout:self.apiClient.timeout success:^(id JSON) { 266 | if (success != nil) 267 | success(self, objectID, JSON); 268 | } failure:^(NSString *errorMessage) { 269 | if (failure != nil) 270 | failure(self, objectID, errorMessage); 271 | }]; 272 | } 273 | 274 | -(AFHTTPRequestOperation *) search:(ASQuery*)query 275 | success:(void(^)(ASRemoteIndex *index, ASQuery *query, NSDictionary *result))success 276 | failure:(void(^)(ASRemoteIndex *index, ASQuery *query, NSString *errorMessage))failure 277 | { 278 | NSString *queryParams = [query buildURL]; 279 | NSString *path = [NSString stringWithFormat:@"/1/indexes/%@/query", self.urlEncodedIndexName]; 280 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObject:queryParams forKey:@"params"]; 281 | return [self performSearchQuery:path method:@"POST" body:dict success:^(id JSON) { 282 | if (success != nil) 283 | success(self, query, JSON); 284 | } failure:^(NSString *errorMessage) { 285 | if (failure != nil) 286 | failure(self, query, errorMessage); 287 | }]; 288 | } 289 | 290 | -(void) cancelPreviousSearches 291 | { 292 | NSString *path = [NSString stringWithFormat:@"/1/indexes/%@/query", self.urlEncodedIndexName]; 293 | [self.apiClient cancelQueries:@"POST" path:path]; 294 | } 295 | 296 | -(AFHTTPRequestOperation *) waitTask:(NSString*)taskID 297 | success:(void(^)(ASRemoteIndex *index, NSString *taskID, NSDictionary *result))success 298 | failure:(void(^)(ASRemoteIndex *index, NSString *taskID, NSString *errorMessage))failure 299 | { 300 | return [self waitTask:taskID withTimeToSleep:0.1f success:success failure:failure]; 301 | } 302 | 303 | -(AFHTTPRequestOperation *) waitTask:(NSString*)taskID withTimeToSleep:(NSTimeInterval)timeToSleep 304 | success:(void(^)(ASRemoteIndex *index, NSString *taskID, NSDictionary *result))success 305 | failure:(void(^)(ASRemoteIndex *index, NSString *taskID, NSString *errorMessage))failure 306 | { 307 | NSString *path = [NSString stringWithFormat:@"/1/indexes/%@/task/%@", self.urlEncodedIndexName, taskID]; 308 | return [self.apiClient performHTTPQuery:path method:@"GET" body:nil managers:self.apiClient.searchOperationManagers index:0 timeout:self.apiClient.timeout success:^(id JSON) { 309 | NSString *status = [JSON valueForKey:@"status"]; 310 | if ([status compare:@"published"] == NSOrderedSame) { 311 | if (success != nil) 312 | success(self, taskID, JSON); 313 | } else { 314 | [NSThread sleepForTimeInterval:timeToSleep]; 315 | [self waitTask:taskID success:success failure:failure]; 316 | } 317 | } failure:^(NSString *errorMessage) { 318 | if (failure != nil) 319 | failure(self, taskID, errorMessage); 320 | }]; 321 | } 322 | 323 | -(AFHTTPRequestOperation *) getSettings:(void(^)(ASRemoteIndex *index, NSDictionary *result))success 324 | failure:(void(^)(ASRemoteIndex *index, NSString *errorMessage))failure 325 | { 326 | NSString *path = [NSString stringWithFormat:@"/1/indexes/%@/settings", self.urlEncodedIndexName]; 327 | return [self.apiClient performHTTPQuery:path method:@"GET" body:nil managers:self.apiClient.searchOperationManagers index:0 timeout:self.apiClient.timeout success:^(id JSON) { 328 | if (success != nil) 329 | success(self, JSON); 330 | } failure:^(NSString *errorMessage) { 331 | if (failure != nil) 332 | failure(self, errorMessage); 333 | }]; 334 | } 335 | 336 | -(AFHTTPRequestOperation *) setSettings:(NSDictionary*)settings 337 | success:(void(^)(ASRemoteIndex *index, NSDictionary *settings, NSDictionary *result))success 338 | failure:(void(^)(ASRemoteIndex *index, NSDictionary *settings, NSString *errorMessage))failure 339 | { 340 | NSString *path = [NSString stringWithFormat:@"/1/indexes/%@/settings", self.urlEncodedIndexName]; 341 | return [self.apiClient performHTTPQuery:path method:@"PUT" body:settings managers:self.apiClient.writeOperationManagers index:0 timeout:self.apiClient.timeout success:^(id JSON) { 342 | if (success != nil) 343 | success(self, settings, JSON); 344 | } failure:^(NSString *errorMessage) { 345 | if (failure != nil) 346 | failure(self, settings, errorMessage); 347 | }]; 348 | } 349 | 350 | -(AFHTTPRequestOperation *) clearIndex:(void(^)(ASRemoteIndex *index, NSDictionary *result))success 351 | failure:(void(^)(ASRemoteIndex *index, NSString *errorMessage))failure 352 | { 353 | NSDictionary *obj = [[NSDictionary alloc] init]; 354 | NSString *path = [NSString stringWithFormat:@"/1/indexes/%@/clear", self.urlEncodedIndexName]; 355 | return [self.apiClient performHTTPQuery:path method:@"POST" body:obj managers:self.apiClient.writeOperationManagers index:0 timeout:self.apiClient.timeout success:^(id JSON) { 356 | if (success != nil) 357 | success(self, JSON); 358 | } failure:^(NSString *errorMessage) { 359 | if (failure != nil) 360 | failure(self, errorMessage); 361 | }]; 362 | } 363 | 364 | -(AFHTTPRequestOperation *) listUserKeys:(void(^)(ASRemoteIndex *index, NSDictionary* result))success 365 | failure:(void(^)(ASRemoteIndex *index, NSString *errorMessage))failure 366 | { 367 | NSString *path = [NSString stringWithFormat:@"/1/indexes/%@/keys", self.urlEncodedIndexName]; 368 | return [self.apiClient performHTTPQuery:path method:@"GET" body:nil managers:self.apiClient.searchOperationManagers index:0 timeout:self.apiClient.timeout success:^(id JSON) { 369 | success(self, JSON); 370 | } failure:^(NSString *errorMessage) { 371 | failure(self, errorMessage); 372 | }]; 373 | } 374 | 375 | -(AFHTTPRequestOperation *) getUserKeyACL:(NSString*)key 376 | success:(void(^)(ASRemoteIndex *index, NSString *key, NSDictionary *result))success 377 | failure:(void(^)(ASRemoteIndex *index, NSString *key, NSString *errorMessage))failure 378 | { 379 | NSString *path = [NSString stringWithFormat:@"/1/indexes/%@/keys/%@", self.urlEncodedIndexName, key]; 380 | return [self.apiClient performHTTPQuery:path method:@"GET" body:nil managers:self.apiClient.searchOperationManagers index:0 timeout:self.apiClient.timeout success:^(id JSON) { 381 | if (success != nil) 382 | success(self, key, JSON); 383 | } failure:^(NSString *errorMessage) { 384 | if (failure != nil) 385 | failure(self, key, errorMessage); 386 | }]; 387 | } 388 | 389 | -(AFHTTPRequestOperation *) browse:(NSUInteger)page 390 | hitsPerPage:(NSUInteger)hitsPerPage 391 | success:(void(^)(ASRemoteIndex *index, NSUInteger page, NSUInteger hitsPerPage, NSDictionary *result))success 392 | failure:(void(^)(ASRemoteIndex *index, NSUInteger page, NSUInteger hitsPerPage, NSString *errorMessage))failure 393 | { 394 | NSString *path = [NSString stringWithFormat:@"/1/indexes/%@/browse?page=%lu&hitsPerPage=%lu", self.urlEncodedIndexName, (unsigned long)page, (unsigned long)hitsPerPage]; 395 | return [self.apiClient performHTTPQuery:path method:@"GET" body:nil managers:self.apiClient.searchOperationManagers index:0 timeout:self.apiClient.timeout success:^(id JSON) { 396 | if (success != nil) 397 | success(self, page, hitsPerPage, JSON); 398 | } failure:^(NSString *errorMessage) { 399 | if (failure != nil) 400 | failure(self, page, hitsPerPage, errorMessage); 401 | }]; 402 | } 403 | 404 | -(AFHTTPRequestOperation *) browse:(NSUInteger)page 405 | success:(void(^)(ASRemoteIndex *index, NSUInteger page, NSDictionary *result))success 406 | failure:(void(^)(ASRemoteIndex *index, NSUInteger page, NSString *errorMessage))failure 407 | { 408 | NSString *path = [NSString stringWithFormat:@"/1/indexes/%@/browse?page=%lu", self.urlEncodedIndexName, (unsigned long)page]; 409 | return [self.apiClient performHTTPQuery:path method:@"GET" body:nil managers:self.apiClient.searchOperationManagers index:0 timeout:self.apiClient.timeout success:^(id JSON) { 410 | if (success != nil) 411 | success(self, page, JSON); 412 | } failure:^(NSString *errorMessage) { 413 | if (failure != nil) 414 | failure(self, page, errorMessage); 415 | }]; 416 | } 417 | 418 | -(void) browseWithQuery:(ASQuery*)query block:(BrowseIteratorHandler)block 419 | { 420 | ASBrowseIterator *iterator = [[ASBrowseIterator alloc] initWithIndex:self query:query cursor:nil andBlock:block]; 421 | [iterator next]; 422 | } 423 | 424 | -(void) browseFromCursor:(NSString*)cursor block:(BrowseIteratorHandler)block 425 | { 426 | ASBrowseIterator *iterator = [[ASBrowseIterator alloc] initWithIndex:self query:nil cursor:cursor andBlock:block]; 427 | [iterator next]; 428 | } 429 | 430 | -(AFHTTPRequestOperation *) deleteUserKey:(NSString*)key 431 | success:(void(^)(ASRemoteIndex *index, NSString *key, NSDictionary *result))success 432 | failure:(void(^)(ASRemoteIndex *index, NSString *key, NSString *errorMessage))failure 433 | { 434 | NSString *path = [NSString stringWithFormat:@"/1/indexes/%@/keys/%@", self.urlEncodedIndexName, key]; 435 | return [self.apiClient performHTTPQuery:path method:@"DELETE" body:nil managers:self.apiClient.writeOperationManagers index:0 timeout:self.apiClient.timeout success:^(id JSON) { 436 | if (success != nil) 437 | success(self, key, JSON); 438 | } failure:^(NSString *errorMessage) { 439 | if (failure != nil) 440 | failure(self, key, errorMessage); 441 | }]; 442 | } 443 | 444 | -(AFHTTPRequestOperation *) addUserKey:(NSArray*)acls 445 | success:(void(^)(ASRemoteIndex *index, NSArray *acls, NSDictionary *result))success 446 | failure:(void(^)(ASRemoteIndex *index, NSArray *acls, NSString *errorMessage))failure 447 | { 448 | NSDictionary *params = [NSMutableDictionary dictionaryWithObject:acls forKey:@"acl"]; 449 | return [self addUserKey:acls withParams:params success:^(ASRemoteIndex *index, NSArray* acls, NSDictionary *params, NSDictionary *result) { 450 | if (success != nil) 451 | success(index, acls, result); 452 | } failure:^(ASRemoteIndex *index, NSArray* acls, NSDictionary *params, NSString *errorMessage) { 453 | if (failure) 454 | failure(index, acls, errorMessage); 455 | }]; 456 | } 457 | 458 | -(AFHTTPRequestOperation *) addUserKey:(NSArray*)acls 459 | withParams:(NSDictionary*)params 460 | success:(void(^)(ASRemoteIndex *index, NSArray* acls, NSDictionary *params, NSDictionary *result))success 461 | failure:(void(^)(ASRemoteIndex *index, NSArray* acls, NSDictionary *params, NSString *errorMessage))failure 462 | { 463 | [params setValue:acls forKey:@"acl"]; 464 | NSString *path = [NSString stringWithFormat:@"/1/indexes/%@/keys", self.urlEncodedIndexName]; 465 | return [self.apiClient performHTTPQuery:path method:@"POST" body:params managers:self.apiClient.writeOperationManagers index:0 timeout:self.apiClient.timeout success:^(id JSON) { 466 | if (success != nil) 467 | success(self, acls, params, JSON); 468 | } failure:^(NSString *errorMessage) { 469 | if (failure != nil) 470 | failure(self, acls, params, errorMessage); 471 | }]; 472 | } 473 | 474 | -(AFHTTPRequestOperation *) addUserKey:(NSArray*)acls 475 | withValidity:(NSUInteger)validity 476 | maxQueriesPerIPPerHour:(NSUInteger)maxQueriesPerIPPerHour 477 | maxHitsPerQuery:(NSUInteger)maxHitsPerQuery 478 | success:(void(^)(ASRemoteIndex *index, NSArray *acls, NSDictionary *result))success 479 | failure:(void(^)(ASRemoteIndex *index, NSArray *acls, NSString *errorMessage))failure; 480 | { 481 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:acls, @"acl", 482 | @(validity), @"validity", 483 | @(maxQueriesPerIPPerHour), @"maxQueriesPerIPPerHour", 484 | @(maxHitsPerQuery), @"maxHitsPerQuery", 485 | nil]; 486 | return [self addUserKey:acls withParams:dict success:^(ASRemoteIndex *index, NSArray* acls, NSDictionary *params, NSDictionary *result) { 487 | if (success != nil) 488 | success(index, acls, result); 489 | } failure:^(ASRemoteIndex *index, NSArray* acls, NSDictionary *params, NSString *errorMessage) { 490 | if (failure) 491 | failure(index, acls, errorMessage); 492 | }]; 493 | } 494 | 495 | -(AFHTTPRequestOperation *) updateUserKey:(NSString*)key 496 | withParams:(NSDictionary*)params 497 | success:(void(^)(ASRemoteIndex *index, NSString *key, NSDictionary *params, NSDictionary *result))success 498 | failure:(void(^)(ASRemoteIndex *index, NSString *key, NSDictionary *params, NSString *errorMessage))failure 499 | { 500 | NSString *path = [NSString stringWithFormat:@"/1/indexes/%@/keys/%@", self.urlEncodedIndexName, key]; 501 | return [self.apiClient performHTTPQuery:path method:@"PUT" body:params managers:self.apiClient.writeOperationManagers index:0 timeout:self.apiClient.timeout success:^(id JSON) { 502 | if (success != nil) 503 | success(self, key, params, JSON); 504 | } failure:^(NSString *errorMessage) { 505 | if (failure != nil) 506 | failure(self, key, params, errorMessage); 507 | }]; 508 | } 509 | 510 | -(AFHTTPRequestOperation *) updateUserKey:(NSString*)key 511 | withACL:(NSArray*)acls 512 | success:(void(^)(ASRemoteIndex *index, NSString *key, NSArray *acls, NSDictionary *result))success 513 | failure:(void(^)(ASRemoteIndex *index, NSString *key, NSArray *acls, NSString *errorMessage))failure 514 | { 515 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObject:acls forKey:@"acl"]; 516 | return [self updateUserKey:key withParams:dict success:^(ASRemoteIndex *index, NSString *key, NSDictionary *params, NSDictionary *result) { 517 | if (success != nil) 518 | success(index, key, acls, result); 519 | } failure:^(ASRemoteIndex *index, NSString *key, NSDictionary *params, NSString *errorMessage) { 520 | if (failure != nil) 521 | failure(index, key, acls, errorMessage); 522 | }]; 523 | } 524 | 525 | -(AFHTTPRequestOperation *) updateUserKey:(NSString*)key 526 | withACL:(NSArray*)acls 527 | withValidity:(NSUInteger)validity 528 | maxQueriesPerIPPerHour:(NSUInteger)maxQueriesPerIPPerHour 529 | maxHitsPerQuery:(NSUInteger)maxHitsPerQuery 530 | success:(void(^)(ASRemoteIndex *index, NSString *key, NSArray *acls, NSDictionary *result))success 531 | failure:(void(^)(ASRemoteIndex *index, NSString *key, NSArray *acls, NSString *errorMessage))failure; 532 | { 533 | NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:acls, @"acl", 534 | @(validity), @"validity", 535 | @(maxQueriesPerIPPerHour), @"maxQueriesPerIPPerHour", 536 | @(maxHitsPerQuery), @"maxHitsPerQuery", 537 | nil]; 538 | return [self updateUserKey:key withParams:dict success:^(ASRemoteIndex *index, NSString *key, NSDictionary *params, NSDictionary *result) { 539 | if (success != nil) 540 | success(index, key, acls, result); 541 | } failure:^(ASRemoteIndex *index, NSString *key, NSDictionary *params, NSString *errorMessage) { 542 | if (failure != nil) 543 | failure(index, key, acls, errorMessage); 544 | }]; 545 | } 546 | 547 | #pragma mark - Search Cache 548 | 549 | - (void)enableSearchCache { 550 | [self enableSearchCacheWithExpiringTimeInterval:120]; 551 | } 552 | 553 | - (void)enableSearchCacheWithExpiringTimeInterval:(NSTimeInterval)eti { 554 | searchCache = [[ASExpiringCache alloc] initWithExpiringTimeInterval:eti]; 555 | } 556 | 557 | - (void)disableSearchCache { 558 | if (searchCache != nil) { 559 | [searchCache clearCache]; 560 | searchCache = nil; 561 | } 562 | } 563 | 564 | - (void)clearSearchCache { 565 | if (searchCache != nil) 566 | [searchCache clearCache]; 567 | } 568 | 569 | - (AFHTTPRequestOperation*)performSearchQuery:(NSString*)path 570 | method:(NSString*)method 571 | body:(NSDictionary*)body 572 | success:(void(^)(id JSON))success 573 | failure:(void(^)(NSString *errorMessage))failure { 574 | 575 | NSString *cacheKey = [NSString stringWithFormat:@"%@_body_%@", path, body]; 576 | 577 | if (searchCache != nil) { 578 | NSDictionary *content = [searchCache objectForKey:cacheKey]; 579 | if (content != nil) { 580 | success(content); 581 | return nil; 582 | } 583 | } 584 | 585 | return [self.apiClient performHTTPQuery:path method:method body:body managers:self.apiClient.searchOperationManagers index:0 timeout:self.apiClient.searchTimeout success:^(id JSON) { 586 | if (searchCache != nil) 587 | [searchCache setObject:JSON forKey:cacheKey]; 588 | 589 | success(JSON); 590 | } failure:failure]; 591 | } 592 | 593 | @end 594 | -------------------------------------------------------------------------------- /test/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /test/test-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | algoliasearch.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | --------------------------------------------------------------------------------