1 /*
2  * Database - Database abstraction layer for D programing language.
3  *
4  * Copyright (C) 2017  Shanghai Putao Technology Co., Ltd
5  *
6  * Developer: HuntLabs
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.database.Database;
13 
14 import hunt.database.DatabaseOption;
15 import hunt.database.Statement;
16 
17 import hunt.database.base;
18 import hunt.database.driver.mysql;
19 import hunt.database.driver.postgresql;
20 import hunt.database.query.QueryBuilder;
21 
22 import hunt.logging;
23 import hunt.net.util.HttpURI;
24 import hunt.util.StringBuilder;
25 
26 import core.time;
27 
28 /**
29  * 
30  */
31 class Database {
32     Pool _pool;
33     DatabaseOption _options;
34 
35     this(string url) {
36         this._options = new DatabaseOption(url);
37         initPool();
38     }
39 
40     this(DatabaseOption options) {
41         this._options = options;
42         initPool();
43     }
44 
45     ~this() {
46         close();
47     }
48 
49     DatabaseOption getOption() {
50         return _options;
51     }
52 
53     Transaction getTransaction(SqlConnection conn) {
54         return conn.begin();
55     }
56 
57     SqlConnection getConnection() {
58         return _pool.getConnection();
59     }
60 
61     void closeConnection(SqlConnection conn) {
62         conn.close();
63     }
64 
65     void relaseConnection(SqlConnection conn) {
66         conn.close();
67     }
68 
69     private void initPool() {
70         import hunt.database.driver.mysql.impl.MySQLPoolImpl;
71         import hunt.database.driver.postgresql.impl.PostgreSQLPoolImpl;
72         import core.time;
73 
74         version (HUNT_DB_DEBUG) {
75             tracef("maximumSize: %d, connectionTimeout: %d, maxWaitQueueSize: %d",
76                     _options.maximumPoolSize, _options.connectionTimeout, _options.maxWaitQueueSize);
77         }
78 
79         // dfmt off
80         PoolOptions poolOptions = new PoolOptions()
81             .setMaxSize(_options.maximumPoolSize)
82             .retry(_options.retry)
83             .awaittingTimeout(_options.connectionTimeout.msecs)
84             .setMaxWaitQueueSize(_options.maxWaitQueueSize);
85 
86         if(_options.isPgsql()) {
87             PgConnectOptions connectOptions = new PgConnectOptions(_options.url);
88             connectOptions.setDecoderBufferSize(_options.getDecoderBufferSize());
89             connectOptions.setEncoderBufferSize(_options.getEncoderBufferSize());
90             connectOptions.setConnectTimeout(_options.connectionTimeout().msecs);
91 
92             _pool = new PgPoolImpl(connectOptions, poolOptions);
93         } else if(_options.isMysql()) {
94             MySQLConnectOptions connectOptions = new MySQLConnectOptions(_options.url);
95             connectOptions.setDecoderBufferSize(_options.getDecoderBufferSize());
96             connectOptions.setEncoderBufferSize(_options.getEncoderBufferSize());
97             connectOptions.setConnectTimeout(_options.connectionTimeout().msecs);
98 
99             _pool = new MySQLPoolImpl(connectOptions, poolOptions);
100 
101         } else {
102             throw new DatabaseException("Unsupported database driver: " ~ _options.schemeName());
103         }
104 
105         // dfmt on
106     }
107 
108     /// return the count of affected rows.
109     int execute(string sql) {
110         RowSet rs = query(sql);
111         return rs.rowCount();
112     }
113 
114     RowSet query(string sql) {
115         version (HUNT_SQL_DEBUG)
116             info(sql);
117         SqlConnection conn = getConnection();
118         scope (exit) {
119             conn.close();
120         }
121 
122         RowSet rs = conn.query(sql);
123         return rs;
124     }
125 
126     Statement prepare(string sql) {
127         SqlConnection conn = getConnection();
128         Statement ret = new Statement(conn, sql, _options);
129         return ret;
130     }
131 
132     Statement prepare(SqlConnection conn, string sql) {
133         Statement ret = new Statement(conn, sql, _options);
134         return ret;
135     }
136 
137     void close() {
138         if (_pool !is null) {
139             _pool.close();
140             _pool = null;
141         }
142     }
143 
144     QueryBuilder createQueryBuilder() {
145         import hunt.sql.util.DBType;
146 
147         if (_options.isPgsql()) {
148             return new QueryBuilder(DBType.POSTGRESQL);
149         } else if (_options.isMysql()) {
150             return new QueryBuilder(DBType.MYSQL);
151         } else {
152             throw new DatabaseException("Unsupported database driver: " ~ _options.schemeName());
153         }
154     }
155 
156     string poolInfo() {
157         if(_pool is null) {
158             return "unset";
159         } else {
160             return (cast(Object)_pool).toString();
161         }
162     }
163 
164 }