1 module vksdk.client.AbstractQueryBuilder; 2 3 import std.conv; 4 import std.uri; 5 6 import vksdk.client.ApiRequest; 7 import vksdk.client.Lang; 8 import vksdk.client.VkApiClient; 9 import vksdk.queries.EnumParam; 10 11 /** 12 * Query builder for API request 13 */ 14 abstract class AbstractQueryBuilder(T, R) : ApiRequest!R { 15 16 private string[string] params; 17 18 private string method; 19 20 /** 21 * Creates a AbstractQueryBuilder instance that can be used to build api request with various parameters 22 * 23 * @param client VK API client 24 * @param method method name 25 * @param type type of method response 26 */ 27 this(VkApiClient client, string method) { 28 super(client.getApiEndpoint() ~ method, client.getTransportClient()); 29 this.method = method; 30 setVersion(client.getVersion); 31 } 32 33 /** 34 * Creates a AbstractQueryBuilder instance that can be used to build api request with various parameters 35 * 36 * @param client VK API client 37 * @param endpoint API endpoint 38 * @param method method name 39 * @param type type of method response 40 */ 41 this(VkApiClient client, string endpoint, string method) { 42 super(endpoint ~ method, client.getTransportClient()); 43 setVersion(client.getVersion); 44 } 45 46 /** 47 * Convert boolean value to integer flag 48 * 49 * @param param value 50 * @return integer flag 51 */ 52 private static string boolAsParam(bool param) { 53 return param ? "1" : "0"; 54 } 55 56 /** 57 * Build request parameter map to query 58 * 59 * @param params parameters 60 * @return string query 61 */ 62 private static string mapToGetString(string[string] params) { 63 string result; 64 65 foreach (key, value; params) { 66 if (result == null) { 67 result = ""; 68 } else { 69 result ~= "&"; 70 } 71 72 result ~= key ~ "=" ~ value != null ? value : ""; 73 } 74 75 return result; 76 } 77 78 /** 79 * Encode request data 80 * 81 * @param data request data 82 * @return encoded data 83 */ 84 private static string escape(string data) { 85 return encode(data); 86 } 87 88 /** 89 * Set access token 90 * 91 * @param value access token 92 * @return a reference to this {@code AbstractQueryBuilder} object to fulfill the "Builder" pattern. 93 */ 94 protected T accessToken(string value) { 95 return unsafeParam("access_token", value); 96 } 97 98 /** 99 * Set lang 100 * 101 * @param value lang 102 * @return a reference to this {@code AbstractQueryBuilder} object to fulfill the "Builder" pattern. 103 */ 104 T lang(Lang value) { 105 return unsafeParam("lang", value.getValue()); 106 } 107 108 /** 109 * Set version 110 * 111 * @param value version 112 * @return a reference to this {@code AbstractQueryBuilder} object to fulfill the "Builder" pattern. 113 */ 114 protected T setVersion(string value) { 115 return unsafeParam("v", value); 116 } 117 118 119 /** 120 * Set captcha sid 121 * 122 * @param value captcha sid 123 * @return a reference to this {@code AbstractQueryBuilder} object to fulfill the "Builder" pattern. 124 */ 125 T captchaSid(string value) { 126 return unsafeParam("captcha_sid", value); 127 } 128 129 /** 130 * Set captcha key 131 * 132 * @param value captcha key 133 * @return a reference to this {@code AbstractQueryBuilder} object to fulfill the "Builder" pattern. 134 */ 135 T captchaKey(string value) { 136 return unsafeParam("captcha_key", value); 137 } 138 139 /** 140 * Set confirmation 141 * 142 * @param value confirm 143 * @return a reference to this {@code AbstractQueryBuilder} object to fulfill the "Builder" pattern. 144 */ 145 T confirm(bool value) { 146 return unsafeParam("confirm", value); 147 } 148 149 150 /** 151 * Set parameter 152 * 153 * @param key name of parameter 154 * @param value value of parameter 155 * @return a reference to this {@code AbstractQueryBuilder} object to fulfill the "Builder" pattern. 156 */ 157 T unsafeParam(string key, string value) { 158 params[key] = value; 159 return getThis(); 160 } 161 162 /** 163 * Set parameter 164 * 165 * @param key name of parameter 166 * @param value value of parameter 167 * @return a reference to this {@code AbstractQueryBuilder} object to fulfill the "Builder" pattern. 168 */ 169 T unsafeParam(string key, int value) { 170 return unsafeParam(key, to!string(value)); 171 } 172 173 /** 174 * Set parameter 175 * 176 * @param key name of parameter 177 * @param value value of parameter 178 * @return a reference to this {@code AbstractQueryBuilder} object to fulfill the "Builder" pattern. 179 */ 180 T unsafeParam(string key, bool value) { 181 return unsafeParam(key, boolAsParam(value)); 182 } 183 184 /** 185 * Set parameter 186 * 187 * @param key name of parameter 188 * @param value value of parameter 189 * @return a reference to this {@code AbstractQueryBuilder} object to fulfill the "Builder" pattern. 190 */ 191 T unsafeParam(string key, T[] values) { 192 string resValue = null; 193 foreach (value; values) { 194 if (resValue == null) { 195 resValue = ""; 196 } else { 197 resValue ~= ","; 198 } 199 200 resValue ~= value.toString; 201 } 202 203 return unsafeParam(key, resValue); 204 } 205 206 /** 207 * Set parameter 208 * 209 * @param key name of parameter 210 * @param value value of parameter 211 * @return a reference to this {@code AbstractQueryBuilder} object to fulfill the "Builder" pattern. 212 */ 213 T unsafeParam(A...)(string key, A values) pure @safe nothrow { 214 A[] resValue; 215 foreach (value; values) { 216 resValue ~= value; 217 } 218 219 return unsafeParam(key, resValue); 220 } 221 222 /** 223 * Set parameter 224 * 225 * @param key name of parameter 226 * @param value value of parameter 227 * @return a reference to this {@code AbstractQueryBuilder} object to fulfill the "Builder" pattern. 228 */ 229 T unsafeParam(string key, int[] values) { 230 string resValue = null; 231 foreach (value; values) { 232 if (resValue == null) { 233 resValue = ""; 234 } else { 235 resValue ~= ","; 236 } 237 238 resValue ~= value; 239 } 240 241 return unsafeParam(key, resValue); 242 } 243 244 /** 245 * Set parameter 246 * 247 * @param key name of parameter 248 * @param value value of parameter 249 * @return a reference to this {@code AbstractQueryBuilder} object to fulfill the "Builder" pattern. 250 */ 251 T unsafeParam(string key, double value) { 252 return unsafeParam(key, to!string(value)); 253 } 254 255 /** 256 * Set parameter 257 * 258 * @param key name of parameter 259 * @param value value of parameter 260 * @return a reference to this {@code AbstractQueryBuilder} object to fulfill the "Builder" pattern. 261 */ 262 T unsafeParam(string key, EnumParam value) { 263 return unsafeParam(key, value.getValue()); 264 } 265 266 /** 267 * Set parameter 268 * 269 * @param key name of parameter 270 * @param fields value of parameter 271 * @return a reference to this {@code AbstractQueryBuilder} object to fulfill the "Builder" pattern. 272 */ 273 T unsafeParam(A...)(string key, EnumParam[] fields) { 274 String resValue = null; 275 foreach (field; fields) { 276 if (resValue == null) { 277 resValue = ""; 278 } else { 279 resValue ~= ","; 280 } 281 282 resValue ~= field.getValue; 283 } 284 285 return unsafeParam(key, resValue); 286 } 287 288 /** 289 * Set parameter 290 * 291 * @param key name of parameter 292 * @param fields value of parameter 293 * @return a reference to this {@code AbstractQueryBuilder} object to fulfill the "Builder" pattern. 294 */ 295 T unsafeParam(string key, EnumParam[] fields) { 296 string resValue = null; 297 foreach (field; fields) { 298 if (resValue == null) { 299 resValue = ""; 300 } else { 301 resValue ~= ","; 302 } 303 304 resValue ~= field.getValue; 305 } 306 307 return unsafeParam(key, resValue); 308 } 309 310 override 311 protected string getBody() { 312 return mapToGetString(build()); 313 } 314 315 /** 316 * Get reference to this object 317 * 318 * @return a reference to this {@code AbstractQueryBuilder} object to fulfill the "Builder" pattern. 319 */ 320 protected abstract T getThis(); 321 322 /** 323 * Get list of required parameter names 324 * 325 * @return list of names 326 */ 327 protected abstract string[] essentialKeys(); 328 329 /** 330 * Get map of parameter values 331 * 332 * @return map of values 333 */ 334 string[string] build() { 335 import std.algorithm; 336 import std.conv; 337 338 // TODO remove 339 // if (!params.keySet().containsAll(essentialKeys())) { 340 341 if (params.keys.all!(a => essentialKeys().canFind(a))) { 342 throw new Exception("Not all the keys are passed: essential keys are " ~to!string(essentialKeys())); 343 } 344 //all!"a > 0"([1, 2, 3, 4]) 345 //if (essentialKeys().all(a => params.canFind(a))) { 346 // throw new Exception("Not all the keys are passed: essential keys are " ~ essentialKeys()); 347 //} 348 349 return params.dup; 350 } 351 352 /** 353 * Get method name 354 * 355 * @return method name 356 */ 357 string getMethod() { 358 return method; 359 } 360 }