001package io.ebean.config;
002
003import io.ebean.annotation.Platform;
004import io.ebean.config.dbplatform.DbType;
005import io.ebean.config.dbplatform.IdType;
006import io.ebean.util.StringHelper;
007
008import java.util.ArrayList;
009import java.util.List;
010import java.util.Map;
011import java.util.Map.Entry;
012
013/**
014 * Configuration for DB types such as UUID, Geometry etc.
015 */
016public class PlatformConfig {
017
018  private boolean allQuotedIdentifiers;
019
020  /**
021   * Set this to true for Postgres FOR UPDATE to use NO KEY option.
022   */
023  private boolean forUpdateNoKey;
024
025  private DbConstraintNaming constraintNaming;
026
027  /**
028   * Flag set when a supplied constraintNaming is used.
029   */
030  private boolean customConstraintNaming;
031
032  /**
033   * The database boolean true value (typically either 1, T, or Y).
034   */
035  private String databaseBooleanTrue;
036
037  /**
038   * The database boolean false value (typically either 0, F or N).
039   */
040  private String databaseBooleanFalse;
041
042  /**
043   * For DB's using sequences this is the number of sequence values prefetched.
044   */
045  private int databaseSequenceBatchSize = 20;
046
047  /**
048   * Set for DB's that support both Sequence and Identity (and the default choice is not desired).
049   */
050  private IdType idType;
051
052  /**
053   * The Geometry SRID value (default 4326).
054   */
055  private int geometrySRID = 4326;
056
057  /**
058   * Setting to indicate if UUID should be stored as binary(16) or varchar(40) or native DB type (for H2 and Postgres).
059   */
060  private DbUuid dbUuid = DbUuid.AUTO_VARCHAR;
061
062  /**
063   * Set to true to force InetAddress to map to Varchar (for Postgres rather than INET)
064   */
065  private boolean databaseInetAddressVarchar;
066
067  private boolean caseSensitiveCollation = true;
068
069  /**
070   * Modify the default mapping of standard types such as default precision for DECIMAL etc.
071   */
072  private List<CustomDbTypeMapping> customDbTypeMappings = new ArrayList<>();
073
074  /**
075   * Construct with defaults.
076   */
077  public PlatformConfig() {
078    this.constraintNaming = new DbConstraintNaming();
079  }
080
081  /**
082   * Construct based on given config - typically for DbMigration generation with many platforms.
083   */
084  public PlatformConfig(PlatformConfig platformConfig) {
085    this.forUpdateNoKey = platformConfig.forUpdateNoKey;
086    this.databaseBooleanFalse = platformConfig.databaseBooleanFalse;
087    this.databaseBooleanTrue = platformConfig.databaseBooleanTrue;
088    this.databaseSequenceBatchSize = platformConfig.databaseSequenceBatchSize;
089    this.idType = platformConfig.idType;
090    this.geometrySRID = platformConfig.geometrySRID;
091    this.dbUuid = platformConfig.dbUuid;
092    this.caseSensitiveCollation = platformConfig.caseSensitiveCollation;
093    this.allQuotedIdentifiers = platformConfig.allQuotedIdentifiers;
094    this.databaseInetAddressVarchar = platformConfig.databaseInetAddressVarchar;
095    this.customDbTypeMappings = platformConfig.customDbTypeMappings;
096    this.constraintNaming = new DbConstraintNaming(!allQuotedIdentifiers);
097  }
098
099  public DbConstraintNaming getConstraintNaming() {
100    return constraintNaming;
101  }
102
103  /**
104   * Set a custom database constraint naming convention.
105   */
106  public void setConstraintNaming(DbConstraintNaming constraintNaming) {
107    this.customConstraintNaming = true;
108    this.constraintNaming = constraintNaming;
109  }
110
111  /**
112   * Return true if all DB column and table names should use quoted identifiers.
113   */
114  public boolean isAllQuotedIdentifiers() {
115    return allQuotedIdentifiers;
116  }
117
118  /**
119   * Set to true if all DB column and table names should use quoted identifiers.
120   */
121  public void setAllQuotedIdentifiers(boolean allQuotedIdentifiers) {
122    this.allQuotedIdentifiers = allQuotedIdentifiers;
123    if (!customConstraintNaming) {
124      this.constraintNaming = new DbConstraintNaming(!allQuotedIdentifiers);
125    }
126  }
127
128  /**
129   * Return true if the collation is case sensitive.
130   */
131  public boolean isCaseSensitiveCollation() {
132    return caseSensitiveCollation;
133  }
134
135  /**
136   * Set to false to indicate that the collation is case insensitive.
137   */
138  public void setCaseSensitiveCollation(boolean caseSensitiveCollation) {
139    this.caseSensitiveCollation = caseSensitiveCollation;
140  }
141
142  /**
143   * Return true if Postgres FOR UPDATE should use the NO KEY option.
144   */
145  public boolean isForUpdateNoKey() {
146    return forUpdateNoKey;
147  }
148
149  /**
150   * Set to true such that Postgres FOR UPDATE should use the NO KEY option.
151   */
152  public void setForUpdateNoKey(boolean forUpdateNoKey) {
153    this.forUpdateNoKey = forUpdateNoKey;
154  }
155
156  /**
157   * Return a value used to represent TRUE in the database.
158   * <p>
159   * This is used for databases that do not support boolean natively.
160   * <p>
161   * The value returned is either a Integer or a String (e.g. "1", or "T").
162   */
163  public String getDatabaseBooleanTrue() {
164    return databaseBooleanTrue;
165  }
166
167  /**
168   * Set the value to represent TRUE in the database.
169   * <p>
170   * This is used for databases that do not support boolean natively.
171   * <p>
172   * The value set is either a Integer or a String (e.g. "1", or "T").
173   */
174  public void setDatabaseBooleanTrue(String databaseBooleanTrue) {
175    this.databaseBooleanTrue = databaseBooleanTrue;
176  }
177
178  /**
179   * Return a value used to represent FALSE in the database.
180   */
181  public String getDatabaseBooleanFalse() {
182    return databaseBooleanFalse;
183  }
184
185  /**
186   * Set the value used to represent FALSE in the database.
187   */
188  public void setDatabaseBooleanFalse(String databaseBooleanFalse) {
189    this.databaseBooleanFalse = databaseBooleanFalse;
190  }
191
192  /**
193   * Return the number of DB sequence values that should be preallocated.
194   */
195  public int getDatabaseSequenceBatchSize() {
196    return databaseSequenceBatchSize;
197  }
198
199  /**
200   * Set the number of DB sequence values that should be preallocated.
201   */
202  public void setDatabaseSequenceBatchSize(int databaseSequenceBatchSize) {
203    this.databaseSequenceBatchSize = databaseSequenceBatchSize;
204  }
205
206  /**
207   * Return the Geometry SRID.
208   */
209  public int getGeometrySRID() {
210    return geometrySRID;
211  }
212
213  /**
214   * Set the Geometry SRID.
215   */
216  public void setGeometrySRID(int geometrySRID) {
217    this.geometrySRID = geometrySRID;
218  }
219
220  /**
221   * Return the DB type used to store UUID.
222   */
223  public DbUuid getDbUuid() {
224    return dbUuid;
225  }
226
227  /**
228   * Set the DB type used to store UUID.
229   */
230  public void setDbUuid(DbUuid dbUuid) {
231    this.dbUuid = dbUuid;
232  }
233
234  /**
235   * Return the IdType to use (or null for the default choice).
236   */
237  public IdType getIdType() {
238    return idType;
239  }
240
241  /**
242   * Set the IdType to use (when the DB supports both SEQUENCE and IDENTITY and the default is not desired).
243   */
244  public void setIdType(IdType idType) {
245    this.idType = idType;
246  }
247
248  /**
249   * Return true if InetAddress should map to varchar column (rather than Postgres INET).
250   */
251  public boolean isDatabaseInetAddressVarchar() {
252    return databaseInetAddressVarchar;
253  }
254
255  /**
256   * Set to true to force InetAddress to map to varchar column.
257   */
258  public void setDatabaseInetAddressVarchar(boolean databaseInetAddressVarchar) {
259    this.databaseInetAddressVarchar = databaseInetAddressVarchar;
260  }
261
262  /**
263   * Add a custom type mapping.
264   * <pre>{@code
265   *
266   *   // set the default mapping for BigDecimal.class/decimal
267   *   config.addCustomMapping(DbType.DECIMAL, "decimal(18,6)");
268   *
269   *   // set the default mapping for String.class/varchar but only for Postgres
270   *   config.addCustomMapping(DbType.VARCHAR, "text", Platform.POSTGRES);
271   *
272   * }</pre>
273   *
274   * @param type             The DB type this mapping should apply to
275   * @param columnDefinition The column definition that should be used
276   * @param platform         Optionally specify the platform this mapping should apply to.
277   */
278  public void addCustomMapping(DbType type, String columnDefinition, Platform platform) {
279    customDbTypeMappings.add(new CustomDbTypeMapping(type, columnDefinition, platform));
280  }
281
282  /**
283   * Add a custom type mapping that applies to all platforms.
284   * <pre>{@code
285   *
286   *   // set the default mapping for BigDecimal/decimal
287   *   config.addCustomMapping(DbType.DECIMAL, "decimal(18,6)");
288   *
289   *   // set the default mapping for String/varchar
290   *   config.addCustomMapping(DbType.VARCHAR, "text");
291   *
292   * }</pre>
293   *
294   * @param type             The DB type this mapping should apply to
295   * @param columnDefinition The column definition that should be used
296   */
297  public void addCustomMapping(DbType type, String columnDefinition) {
298    customDbTypeMappings.add(new CustomDbTypeMapping(type, columnDefinition));
299  }
300
301  /**
302   * Return the list of custom type mappings.
303   */
304  public List<CustomDbTypeMapping> getCustomTypeMappings() {
305    return customDbTypeMappings;
306  }
307
308  public void loadSettings(PropertiesWrapper p) {
309
310    idType = p.getEnum(IdType.class, "idType", idType);
311    forUpdateNoKey = p.getBoolean("forUpdateNoKey", forUpdateNoKey);
312    databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", databaseSequenceBatchSize);
313    databaseBooleanTrue = p.get("databaseBooleanTrue", databaseBooleanTrue);
314    databaseBooleanFalse = p.get("databaseBooleanFalse", databaseBooleanFalse);
315    databaseInetAddressVarchar = p.getBoolean("databaseInetAddressVarchar", databaseInetAddressVarchar);
316    caseSensitiveCollation = p.getBoolean("caseSensitiveCollation", caseSensitiveCollation);
317
318    DbUuid dbUuid = p.getEnum(DbUuid.class, "dbuuid", null);
319    if (dbUuid != null) {
320      setDbUuid(dbUuid);
321    }
322    if (p.getBoolean("uuidStoreAsBinary", false)) {
323      setDbUuid(DbUuid.BINARY);
324    }
325
326    int srid = p.getInt("geometrySRID", 0);
327    if (srid > 0) {
328      setGeometrySRID(srid);
329    }
330
331    // Mapping is specified in the form: BOOLEAN=int(1);BIT=int(1);
332    String mapping = p.get("mapping");
333    if (mapping != null && !mapping.isEmpty()) {
334      Map<String, String> map = StringHelper.delimitedToMap(mapping, ";", "=");
335      for (Entry<String, String> entry : map.entrySet()) {
336        addCustomMapping(DbType.valueOf(entry.getKey()), entry.getValue());
337      }
338    }
339
340    boolean quotedIdentifiers = p.getBoolean("allQuotedIdentifiers", allQuotedIdentifiers);
341    if (quotedIdentifiers != allQuotedIdentifiers) {
342      // potentially also set to use matching naming convention
343      setAllQuotedIdentifiers(quotedIdentifiers);
344    }
345  }
346
347  /**
348   * Specify how UUID is stored.
349   */
350  public enum DbUuid {
351
352    /**
353     * Store using native UUID in H2 and Postgres and otherwise fallback to VARCHAR(40).
354     */
355    AUTO_VARCHAR(true, false, false),
356
357    /**
358     * Store using native UUID in H2 and Postgres and otherwise fallback to BINARY(16).
359     */
360    AUTO_BINARY(true, true, false),
361
362    /**
363     * Store using native UUID in H2 and Postgres and otherwise fallback to BINARY(16) with optimized packing.
364     */
365    AUTO_BINARY_OPTIMIZED(true, true, true),
366
367    /**
368     * Store using DB VARCHAR(40).
369     */
370    VARCHAR(false, false, false),
371
372    /**
373     * Store using DB BINARY(16).
374     */
375    BINARY(false, true, false),
376
377    /**
378     * Store using DB BINARY(16).
379     */
380    BINARY_OPTIMIZED(false, true, true);
381
382    boolean nativeType;
383    boolean binary;
384    boolean binaryOptimized;
385
386    DbUuid(boolean nativeType, boolean binary, boolean binaryOptimized) {
387      this.nativeType = nativeType;
388      this.binary = binary;
389      this.binaryOptimized = binaryOptimized;
390    }
391
392    /**
393     * Return true if native UUID type is preferred.
394     */
395    public boolean useNativeType() {
396      return nativeType;
397    }
398
399    /**
400     * Return true if BINARY(16) storage is preferred over VARCHAR(40).
401     */
402    public boolean useBinary() {
403      return binary;
404    }
405
406    /**
407     * Return true, if optimized packing should be used.
408     */
409    public boolean useBinaryOptimized() {
410      return binaryOptimized;
411    }
412  }
413}