1 /++ 2 Connect to a MySQL/MariaDB database using vibe.d's 3 $(LINK2 http://vibed.org/api/vibe.core.connectionpool/ConnectionPool, ConnectionPool). 4 5 You have to include vibe.d in your project to be able to use this class. 6 If you don't want to, refer to `mysql.connection.Connection`. 7 8 This provides various benefits over creating a new connection manually, 9 such as automatically reusing old connections, and automatic cleanup (no need to close 10 the connection when done). 11 +/ 12 module mysql.pool; 13 14 import std.conv; 15 import mysql.connection; 16 import mysql.protocol.constants; 17 debug(MYSQLN_TESTS) 18 { 19 import mysql.test.common; 20 } 21 22 version(Have_vibe_d_core) version = IncludeMySQLPool; 23 version(MySQLDocs) version = IncludeMySQLPool; 24 25 version(IncludeMySQLPool) 26 { 27 version(Have_vibe_d_core) 28 import vibe.core.connectionpool; 29 else 30 { 31 /++ 32 Vibe.d's 33 $(LINK2 http://vibed.org/api/vibe.core.connectionpool/ConnectionPool, ConnectionPool) 34 class. 35 36 Not actually included in module `mysql.pool`. Only listed here for 37 documentation purposes. For ConnectionPool and it's documentation, see: 38 $(LINK http://vibed.org/api/vibe.core.connectionpool/ConnectionPool) 39 +/ 40 class ConnectionPool(T) 41 { 42 /// See: $(LINK http://vibed.org/api/vibe.core.connectionpool/ConnectionPool.this) 43 this(Connection delegate() connection_factory, uint max_concurrent = (uint).max) 44 {} 45 46 /// See: $(LINK http://vibed.org/api/vibe.core.connectionpool/ConnectionPool.lockConnection) 47 LockedConnection!T lockConnection() { return LockedConnection!T(); } 48 49 /// See: $(LINK http://vibed.org/api/vibe.core.connectionpool/ConnectionPool.maxConcurrency) 50 uint maxConcurrency; 51 } 52 53 /++ 54 Vibe.d's 55 $(LINK2 http://vibed.org/api/vibe.core.connectionpool/LockedConnection, LockedConnection) 56 struct. 57 58 Not actually included in module `mysql.pool`. Only listed here for 59 documentation purposes. For LockedConnection and it's documentation, see: 60 $(LINK http://vibed.org/api/vibe.core.connectionpool/LockedConnection) 61 +/ 62 struct LockedConnection(Connection) {} 63 } 64 65 /++ 66 A lightweight convenience interface to a MySQL/MariaDB database using vibe.d's 67 $(LINK2 http://vibed.org/api/vibe.core.connectionpool/ConnectionPool, ConnectionPool). 68 69 You have to include vibe.d in your project to be able to use this class. 70 If you don't want to, refer to `mysql.connection.Connection`. 71 72 If, for any reason, this class doesn't suit your needs, it's easy to just 73 use vibe.d's $(LINK2 http://vibed.org/api/vibe.core.connectionpool/ConnectionPool, ConnectionPool) 74 directly. Simply provide it with a delegate that creates a new `mysql.connection.Connection` 75 and does any other custom processing if needed. 76 +/ 77 class MySQLPool { 78 private { 79 string m_host; 80 string m_user; 81 string m_password; 82 string m_database; 83 ushort m_port; 84 SvrCapFlags m_capFlags; 85 void delegate(Connection) m_onNewConnection; 86 ConnectionPool!Connection m_pool; 87 } 88 89 /// Sets up a connection pool with the provided connection settings. 90 /// 91 /// The optional `onNewConnection` param allows you to set a callback 92 /// which will be run every time a new connection is created. 93 this(string host, string user, string password, string database, 94 ushort port = 3306, uint maxConcurrent = (uint).max, 95 SvrCapFlags capFlags = defaultClientFlags, 96 void delegate(Connection) onNewConnection = null) 97 { 98 m_host = host; 99 m_user = user; 100 m_password = password; 101 m_database = database; 102 m_port = port; 103 m_capFlags = capFlags; 104 m_onNewConnection = onNewConnection; 105 m_pool = new ConnectionPool!Connection(&createConnection); 106 } 107 108 ///ditto 109 this(string host, string user, string password, string database, 110 ushort port, SvrCapFlags capFlags, void delegate(Connection) onNewConnection = null) 111 { 112 this(host, user, password, database, port, (uint).max, capFlags, onNewConnection); 113 } 114 115 ///ditto 116 this(string host, string user, string password, string database, 117 ushort port, void delegate(Connection) onNewConnection) 118 { 119 this(host, user, password, database, port, (uint).max, defaultClientFlags, onNewConnection); 120 } 121 122 ///ditto 123 this(string connStr, uint maxConcurrent = (uint).max, SvrCapFlags capFlags = defaultClientFlags, 124 void delegate(Connection) onNewConnection = null) 125 { 126 auto parts = Connection.parseConnectionString(connStr); 127 this(parts[0], parts[1], parts[2], parts[3], to!ushort(parts[4]), capFlags, onNewConnection); 128 } 129 130 ///ditto 131 this(string connStr, SvrCapFlags capFlags, void delegate(Connection) onNewConnection = null) 132 { 133 this(connStr, (uint).max, capFlags, onNewConnection); 134 } 135 136 ///ditto 137 this(string connStr, void delegate(Connection) onNewConnection) 138 { 139 this(connStr, (uint).max, defaultClientFlags, onNewConnection); 140 } 141 142 /++ 143 Obtain a connection. If one isn't available, a new one will be created. 144 145 The connection returned is actually a `LockedConnection!Connection`, 146 but it uses `alias this`, and so can be used just like a Connection. 147 (See vibe.d's 148 $(LINK2 http://vibed.org/api/vibe.core.connectionpool/LockedConnection, LockedConnection documentation).) 149 150 No other fiber will be given this `mysql.connection.Connection` as long as your fiber still holds it. 151 152 There is no need to close, release or unlock this connection. It is 153 reference-counted and will automatically be returned to the pool once 154 your fiber is done with it. 155 +/ 156 auto lockConnection() { return m_pool.lockConnection(); } 157 158 private Connection createConnection() 159 { 160 auto conn = new Connection(m_host, m_user, m_password, m_database, m_port, m_capFlags); 161 162 if(m_onNewConnection) 163 m_onNewConnection(conn); 164 165 return conn; 166 } 167 168 169 /// Get/set a callback delegate to be run every time a new connection 170 /// is created. 171 @property void onNewConnection(void delegate(Connection) onNewConnection) 172 { 173 m_onNewConnection = onNewConnection; 174 } 175 176 ///ditto 177 @property void delegate(Connection) onNewConnection() 178 { 179 return m_onNewConnection; 180 } 181 182 debug(MYSQLN_TESTS) 183 unittest 184 { 185 auto count = 0; 186 void callback(Connection conn) 187 { 188 count++; 189 } 190 191 // Test getting/setting 192 auto poolA = new MySQLPool(testConnectionStr, &callback); 193 auto poolB = new MySQLPool(testConnectionStr); 194 auto poolNoCallback = new MySQLPool(testConnectionStr); 195 196 assert(poolA.onNewConnection == &callback); 197 assert(poolB.onNewConnection is null); 198 assert(poolNoCallback.onNewConnection is null); 199 200 poolB.onNewConnection = &callback; 201 assert(poolB.onNewConnection == &callback); 202 assert(count == 0); 203 204 // Ensure callback is called 205 { 206 auto connA = poolA.lockConnection(); 207 assert(!connA.closed); 208 assert(count == 1); 209 210 auto connB = poolB.lockConnection(); 211 assert(!connB.closed); 212 assert(count == 2); 213 } 214 215 // Ensure works with no callback 216 { 217 auto oldCount = count; 218 auto poolC = new MySQLPool(testConnectionStr); 219 auto connC = poolC.lockConnection(); 220 assert(!connC.closed); 221 assert(count == oldCount); 222 } 223 } 224 225 226 /++ 227 Forwards to vibe.d's 228 $(LINK2 http://vibed.org/api/vibe.core.connectionpool/ConnectionPool.maxConcurrency, ConnectionPool.maxConcurrency) 229 +/ 230 @property uint maxConcurrency() 231 { 232 return m_pool.maxConcurrency; 233 } 234 235 ///ditto 236 @property void maxConcurrency(uint maxConcurrent) 237 { 238 m_pool.maxConcurrency = maxConcurrent; 239 } 240 } 241 }