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