001/* 002 * JKNIV, whinstone one contract to access your database. 003 * 004 * Copyright (C) 2017, the original author or authors. 005 * 006 * This library is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 2.1 of the License. 010 * 011 * This library is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public 017 * License along with this library; if not, write to the Free Software Foundation, Inc., 018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 019 */ 020package net.sf.jkniv.whinstone; 021 022import java.util.Comparator; 023import java.util.HashMap; 024import java.util.Map; 025 026import net.sf.jkniv.asserts.Assertable; 027import net.sf.jkniv.asserts.AssertsFactory; 028import net.sf.jkniv.whinstone.types.RegisterType; 029 030public class QueryFactory 031{ 032 private static final Assertable NOT_NULL = AssertsFactory.getNotNull(); 033 034 QueryFactory() { /* no instance for this */ } 035 036 /** 037 * Creates a Query object parameterized starting at first row and retrieve all rows, isolation default, no timeout and online (no batch). 038 * 039 * @param name query name 040 * @param params dynamically arguments to create {@code Queryable}. 041 * <p> 042 * 1o first param it's key name and 2o your value 043 * <p> 044 * 3o it's key 4o your value and so on. 045 * @return Queryable object with unlimited result 046 */ 047 public static Queryable of(String name, Object... params) 048 { 049 NOT_NULL.verify(name); 050 return buildQueryable(name, 0, Integer.MAX_VALUE, null, params); 051 } 052 053 public static Queryable of(String name, RegisterType registerType, Object... args) 054 { 055 NOT_NULL.verify(name, registerType); 056 return buildQueryable(name, 0, Integer.MAX_VALUE, registerType, args); 057 } 058 059 /** 060 * Creates a {@link Queryable} object parameterized starting at first row and retrieve all rows, 061 * isolation default, no timeout and online (no batch). 062 * 063 * @param name query name 064 * @param params parameters of query 065 * @return Queryable object with parameters and unlimited result 066 */ 067 public static Queryable of(String name, Object params) 068 { 069 NOT_NULL.verify(name, params); 070 return new QueryName(name, params, 0, Integer.MAX_VALUE); 071 } 072 073 /** 074 * Creates a {@link Queryable} object parameterized starting at first row and retrieve all rows, 075 * isolation default, no timeout and online (no batch). 076 * 077 * @param name query name 078 * @param params array of parameters 079 * @return Queryable object with parameters and unlimited result 080 */ 081 public static Queryable ofArray(String name, Object... params) 082 { 083 NOT_NULL.verify(name, params); 084 return new QueryName(name, params, 0, Integer.MAX_VALUE); 085 } 086 087 public static Queryable ofArray(String name, RegisterType registerType, Object... params) 088 { 089 NOT_NULL.verify(name, registerType, params); 090 return new QueryName(name, params, 0, Integer.MAX_VALUE, registerType); 091 } 092 093 /** 094 * Build a new {@code Queryable} object 095 * 096 * @param name a name for query 097 * @param params parameters from query 098 * @param offset the first row 099 * @param max row numbers 100 * @return Queryable object with parameters and limited result starting at {@code offset} and {@code max} rows. 101 */ 102 public static Queryable of(String name, Object params, int offset, int max) 103 { 104 NOT_NULL.verify(name, name, params); 105 return new QueryName(name, params, offset, max); 106 } 107 108 /** 109 * Build a new {@code Queryable} object without parameters 110 * 111 * @param name a name for query 112 * @param offset the first row 113 * @param max row numbers 114 * @return Queryable object with parameters and limited result starting at {@code offset} and {@code max} rows. 115 */ 116 public static Queryable of(String name, int offset, int max) 117 { 118 NOT_NULL.verify(name); 119 return new QueryName(name, null, offset, max); 120 } 121 122 /** 123 * Build a new {@code Queryable} object 124 * @param name query name 125 * @param returnType return type that overload return type from XML 126 * @param args dynamically arguments to create {@code Queryable}. 127 * <p> 128 * 1o first param it's key name and 2o your value 129 * <p> 130 * 3o it's key 4o your value and so on. 131 * @param <T> type of return type 132 * @return {@link Queryable} object with parameters and unlimited result and specific return type 133 */ 134 public static <T> Queryable of(String name, Class<T> returnType, Object... args) 135 { 136 NOT_NULL.verify(name, returnType, args); 137 QueryName q = (QueryName) buildQueryable(name, 0, Integer.MAX_VALUE, null, args); 138 q.setReturnType(returnType); 139 return q; 140 } 141 142 /** 143 * Creates a {@link Queryable} object parameterized starting at first row and retrieve all rows, 144 * isolation default, no timeout and online (no batch). 145 * 146 * @param name query name 147 * @param returnType return type that overload return type from XML 148 * @param params parameters of query 149 * @param <T> class type of overload return 150 * @return {@link Queryable} object with parameters and unlimited result 151 */ 152 public static <T> Queryable of(String name, Class<T> returnType, Object params) 153 { 154 NOT_NULL.verify(name, returnType, params); 155 QueryName q = new QueryName(name, params); 156 q.setReturnType(returnType); 157 return q; 158 } 159 160 /** 161 * Build a new {@link Queryable} object 162 * @param name query name 163 * @param returnType return type that overload return type from XML 164 * @param <T> type of return type 165 * @return {@link Queryable} object with parameters and unlimited result and specific return type 166 */ 167 public static <T> Queryable of(String name, Class<T> returnType) 168 { 169 NOT_NULL.verify(name, returnType); 170 QueryName q = new QueryName(name); 171 q.setReturnType(returnType); 172 return q; 173 } 174 175 public static <T> Queryable clone(Queryable queryable) 176 { 177 NOT_NULL.verify(queryable); 178 return clone(queryable.getName(), queryable, queryable.getParams(), queryable.getRegisterType(), null); 179 } 180 181 /** 182 * Clone {@code queryable} object with a return type if no {@code null} 183 * @param queryable query name 184 * @param returnType type of return that overload return type from XML 185 * @param <T> type of return type 186 * @return clone of Queryable instance 187 */ 188 public static <T> Queryable clone(Queryable queryable, Class<T> returnType) 189 { 190 NOT_NULL.verify(queryable, returnType); 191 return clone(queryable.getName(), queryable, queryable.getParams(), queryable.getRegisterType(), returnType); 192 } 193 194 /** 195 * Clone {@code queryable} object with a return type if no {@code null} 196 * @param queryable query name 197 * @param registerType registry of type data 198 * @param <T> type of return type 199 * @return clone of Queryable instance 200 */ 201 public static <T> Queryable clone(Queryable queryable, RegisterType registerType) 202 { 203 NOT_NULL.verify(queryable, registerType); 204 return clone(queryable.getName(), queryable, queryable.getParams(), registerType, null); 205 } 206 207 public static <T> Queryable clone(Queryable queryable, RegisterType registerType, Class<T> returnType) 208 { 209 NOT_NULL.verify(queryable, registerType); 210 return clone(queryable.getName(), queryable, queryable.getParams(), registerType, returnType); 211 } 212 213 /** 214 * Clone {@code queryable} object with a return type if no {@code null} 215 * @param queryName of new query 216 * @param queryable query instance 217 * @param params parameter of new query 218 * @param registerType registry of type data 219 * @param returnType type of return that overload return type from XML 220 * @param <T> type of return type 221 * @return new instance of Queryable instance 222 */ 223 public static <T> Queryable clone(String queryName, Queryable queryable, Object params, RegisterType registerType, Class<T> returnType) 224 { 225 QueryName q = new QueryName(queryName, params, queryable.getOffset(), queryable.getMax(), registerType); 226 227 if (returnType != null) 228 q.setReturnType(returnType); 229 else if (queryable.hasReturnType()) 230 q.setReturnType(queryable.getReturnType()); 231 232 if(queryable.isCacheIgnore()) 233 q.cacheIgnore(); 234 235 if(queryable.isScalar()) 236 q.scalar(); 237 238 q.setSorter(queryable.getSorter()); 239 q.setFilter(queryable.getFilter()); 240 q.setBookmark(queryable.getBookmark()); 241 return q; 242 } 243 244// public static Queryable of(String name, List params) 245// { 246// return new QueryName(name, params, 0, Integer.MAX_VALUE); 247// } 248// 249// /** 250// * Build a new {@code Queryable} object 251// * @param name query name 252// * @param offset the first row 253// * @param max row numbers 254// * @param args dynamically arguments to create {@code Queryable}. 255// * <p> 256// * 1o first param it's key name and 2o your value 257// * <p> 258// * 3o it's key 4o your value and so on. 259// * @return Queryable object with parameters with limited result by {@code max} 260// */ 261// public static Queryable of(String name, int offset, int max, Object... args) 262// { 263// QueryName q = (QueryName) buildQueryable(name, args); 264// q.setOffset(offset); 265// q.setMax(max); 266// return q; 267// } 268 /* 269 * @param name query name 270 * @param returnType type of return that overload return type from XML 271 * @param offset the first row 272 * @param max row numbers 273 * @param args dynamically arguments to create {@code Queryable}. 274 * @param <T> type of return type 275 * <p> 276 * 1o first param it's key name and 2o your value 277 * <p> 278 * 3o it's key 4o your value and so on. 279 * @return Queryable object with parameters and limited result starting at {@code offset} and {@code max} rows. 280 * 281 public static <T> Queryable of(String name, Class<T> returnType, int offset, int max, Object... args) 282 { 283 QueryName q = (QueryName) buildQueryable(name, args); 284 q.setOffset(offset); 285 q.setMax(max); 286 q.setReturnType(returnType); 287 return q; 288 } 289 */ 290 291 /** 292 * Create new instance of {@code Queryable} without out pagination. 293 * @param name query name 294 * @param args dynamically arguments to create {@code queryable}. 295 * <p> 296 * 1º first param it's name of {@code queryable} object 297 * <p> 298 * 2º and 3º are pair of name and value of first parameter and so on 4º/5º are second, etc. 299 * @return new instance of Queryable with your parameters 300 */ 301 private static Queryable buildQueryable(String name, int offset, int max, RegisterType registerType, Object... args) 302 { 303 NOT_NULL.verify(args); 304 Queryable queryable = null; 305 if (args.length == 1) 306 { 307 queryable = new QueryName(name, args[0], offset, max, registerType); 308 } 309 else 310 { 311 Map<String, Object> params = buildParams(args); 312 if (params.size() > 0 ) 313 queryable = new QueryName(name, params, offset, max, registerType); 314 else 315 queryable = new QueryName(name, null, offset, max, registerType); 316 } 317 return queryable; 318 } 319 320 static Map<String, Object> buildParams(Object... args) 321 { 322 Map<String, Object> params = new HashMap<String, Object>(); 323 int i = 0; 324 Object value = null; 325 String key = null; 326 for (Object o : args) 327 { 328 if (i % 2 == 0) 329 { 330 key = o.toString(); 331 } 332 else 333 { 334 value = o; 335 params.put(key, value); 336 key = null; 337 value = null; 338 } 339 i++; 340 } 341 return params; 342 } 343 344 /* ********************************************************************************************************************* 345 * ==============> B U I L D E R <============ * 346 * *********************************************************************************************************************/ 347 348 public static Builder builder() 349 { 350 return new Builder(); 351 } 352 353 public static class Builder 354 { 355 private Map<String, Object> mapParams = new HashMap<String, Object>(); 356 private Object[] arrayOfParams; 357 private Object params; 358 private int offset; 359 private int max = Integer.MAX_VALUE; 360 private boolean scalar = false; 361 private RegisterType registerType; 362 private Class<?> returnType; 363 private Comparator<?> sorter; 364 private Filter<?> filter; 365 366 public Queryable build(String name) { 367 QueryName q = null; 368 if (arrayOfParams != null) 369 q = new QueryName(name, arrayOfParams, offset, max, registerType); 370 else if (params != null) 371 q = new QueryName(name, params, offset, max, registerType); 372 else if (!mapParams.isEmpty()) 373 q = new QueryName(name, mapParams, offset, max, registerType); 374 else 375 q = new QueryName(name, null, offset, max, registerType); 376 377 q.setReturnType(returnType); 378 q.setSorter(sorter); 379 q.setFilter(filter); 380 if(this.scalar) 381 q.scalar(); 382 return q; 383 } 384 /** 385 * Build the query parameters as Map 386 * <p> <b>note:</b> don't mix the set {@code param} values and {@code ofArray} </p> 387 * @param params dynamically created 388 * <p> 389 * 1o first param it's key name and 2o your value 390 * <p> 391 * 3o it's key 4o your value and so on. 392 * @return this builder instance 393 */ 394 public Builder params(Object... params) { 395 this.mapParams = QueryFactory.buildParams(params); 396 return this; 397 } 398 /** 399 * Build the query parameters as Map. 400 * <p> <b>note:</b> don't mix the set {@code param} values and {@code ofArray} </p> 401 * @param name parameter 402 * @param value parameter 403 * @return this builder instance 404 */ 405 public Builder params(String name, Object value) { 406 this.mapParams.put(name, value); 407 return this; 408 } 409 /** 410 * Build the query parameters as POJO 411 * <p> <b>note:</b> don't mix the set {@code param} values and {@code ofArray} </p> 412 * @param <T> Type of class that represents the parameters 413 * @param param instance of class the represents the parameters 414 * @return this builder instance 415 */ 416 public <T> Builder params(T param) { 417 this.params = param; 418 return this; 419 } 420 /** 421 * Build the query parameters as array of values. 422 * <p> <b>note:</b> don't mix the set {@code param} values and {@code ofArray} </p> 423 * @param params array of parameters 424 * @return this builder instance 425 */ 426 public Builder ofArray(Object... params) { 427 this.arrayOfParams = params; 428 return this; 429 } 430 public Builder offset(int offset) { 431 this.offset = offset; 432 return this; 433 } 434 public Builder max(int max) { 435 this.max = max; 436 return this; 437 } 438 public Builder registerType(RegisterType registerType) { 439 this.registerType = registerType; 440 return this; 441 } 442 public Builder returnType(Class<?> returnType) { 443 this.returnType = returnType; 444 return this; 445 } 446 public Builder sorter(Comparator<?> sorter) { 447 this.sorter = sorter; 448 return this; 449 } 450 public Builder filter(Filter<?> filter) { 451 this.filter = filter; 452 return this; 453 } 454 public Builder scalar() { 455 this.scalar = true; 456 return this; 457 } 458 } 459}