|
8 | 8 | from typing import List
|
9 | 9 | from typing import Optional
|
10 | 10 | from typing import Type
|
| 11 | +from urllib.parse import quote |
| 12 | +from urllib.parse import quote_plus |
11 | 13 |
|
12 | 14 | import sqlalchemy.sql.elements as se
|
13 | 15 | from sqlalchemy import util
|
@@ -318,6 +320,33 @@ def result_processor(self, dialect: Any, coltype: Any) -> Any:
|
318 | 320 | return None
|
319 | 321 |
|
320 | 322 |
|
| 323 | +def render_as_string(url: URL) -> str: |
| 324 | + s = url.drivername + '://' |
| 325 | + if url.username is not None: |
| 326 | + s += quote(url.username) |
| 327 | + if url.password is not None: |
| 328 | + s += ':' + quote(str(url.password)) |
| 329 | + s += '@' |
| 330 | + if url.host is not None: |
| 331 | + if ':' in url.host: |
| 332 | + s += f'[{url.host}]' |
| 333 | + else: |
| 334 | + s += url.host |
| 335 | + if url.port is not None: |
| 336 | + s += ':' + str(url.port) |
| 337 | + if url.database is not None: |
| 338 | + s += '/' + url.database |
| 339 | + if url.query: |
| 340 | + keys = list(url.query) |
| 341 | + keys.sort() |
| 342 | + s += '?' + '&'.join( |
| 343 | + f'{quote_plus(k)}={quote_plus(element)}' |
| 344 | + for k in keys |
| 345 | + for element in util.to_list(url.query[k]) |
| 346 | + ) |
| 347 | + return s |
| 348 | + |
| 349 | + |
321 | 350 | class SingleStoreDBDialect(MySQLDialect):
|
322 | 351 | """SingleStoreDB SQLAlchemy dialect."""
|
323 | 352 |
|
@@ -383,7 +412,7 @@ def initialize(self, connection: Any) -> Any:
|
383 | 412 |
|
384 | 413 | def create_connect_args(self, url: URL) -> List[Any]:
|
385 | 414 | from singlestoredb.connection import build_params
|
386 |
| - return [[], build_params(host=url.render_as_string(hide_password=False))] |
| 415 | + return [[], build_params(host=render_as_string(url))] |
387 | 416 |
|
388 | 417 | def _extract_error_code(self, exception: Exception) -> int:
|
389 | 418 | return getattr(exception, 'errno', -1)
|
|
0 commit comments