6
6
# @Filename: database.py
7
7
# @License: BSD 3-clause (http://www.opensource.org/licenses/BSD-3-Clause)
8
8
9
+ from __future__ import annotations
10
+
9
11
import abc
10
12
import importlib
11
13
import os
12
14
import re
13
15
import socket
14
16
17
+ import peewee
15
18
import pgpasslib
16
19
import six
17
-
20
+ from peewee import OperationalError , PostgresqlDatabase
21
+ from playhouse .postgres_ext import ArrayField
22
+ from playhouse .reflection import Introspector , UnknownField
18
23
from sqlalchemy import MetaData , create_engine
19
24
from sqlalchemy .engine import url
20
25
from sqlalchemy .exc import OperationalError as OpError
21
26
from sqlalchemy .orm import scoped_session , sessionmaker
22
27
23
- import peewee
24
- from peewee import OperationalError , PostgresqlDatabase
25
- from playhouse .postgres_ext import ArrayField
26
- from playhouse .reflection import Introspector , UnknownField
27
-
28
28
import sdssdb
29
29
from sdssdb import config , log
30
30
from sdssdb .utils .internals import get_database_columns
31
31
32
-
33
32
__all__ = ['DatabaseConnection' , 'PeeweeDatabaseConnection' , 'SQLADatabaseConnection' ]
34
33
35
34
@@ -44,6 +43,30 @@ def _should_autoconnect():
44
43
return sdssdb .autoconnect
45
44
46
45
46
+ def get_database_uri (
47
+ dbname : str ,
48
+ host : str | None = None ,
49
+ port : int | None = None ,
50
+ user : str | None = None ,
51
+ password : str | None = None ,
52
+ ):
53
+ """Returns the URI to the database."""
54
+
55
+ if user is None and password is None :
56
+ auth : str = ""
57
+ elif password is None :
58
+ auth : str = f"{ user } @"
59
+ else :
60
+ auth : str = f"{ user } :{ password } @"
61
+
62
+ host_port : str = f"{ host or '' } " if port is None else f"{ host or '' } :{ port } "
63
+
64
+ if auth == "" and host_port == "" :
65
+ return f"postgresql://{ dbname } "
66
+
67
+ return f"postgresql://{ auth } { host_port } /{ dbname } "
68
+
69
+
47
70
class DatabaseConnection (six .with_metaclass (abc .ABCMeta )):
48
71
"""A PostgreSQL database connection with profile and autoconnect features.
49
72
@@ -109,7 +132,7 @@ def __repr__(self):
109
132
return '<{} (dbname={!r}, profile={!r}, connected={})>' .format (
110
133
self .__class__ .__name__ , self .dbname , self .profile , self .connected )
111
134
112
- def set_profile (self , profile = None , connect = True ):
135
+ def set_profile (self , profile = None , connect = True , ** params ):
113
136
"""Sets the profile from the configuration file.
114
137
115
138
Parameters
@@ -119,6 +142,9 @@ def set_profile(self, profile=None, connect=True):
119
142
determine the profile.
120
143
connect : bool
121
144
If True, tries to connect to the database using the new profile.
145
+ params
146
+ Connection parameters (``user``, ``host``, ``port``, ``password``)
147
+ that will override the profile values.
122
148
123
149
Returns
124
150
-------
@@ -157,6 +183,8 @@ def set_profile(self, profile=None, connect=True):
157
183
self ._config ['host' ] = None
158
184
break
159
185
186
+ self ._config .update (params )
187
+
160
188
if connect :
161
189
if self .connected and self .profile == previous_profile :
162
190
pass
@@ -276,7 +304,16 @@ def list_profiles(profile=None):
276
304
277
305
return config [profile ]
278
306
279
- @abc .abstractproperty
307
+ def get_connection_uri (self ):
308
+ """Returns the URI to the database connection."""
309
+
310
+ params = self .connection_params
311
+ if not self .connected or params is None :
312
+ raise RuntimeError ('The database is not connected.' )
313
+
314
+ return get_database_uri (self .dbname , ** params )
315
+
316
+ @abc .abstractmethod
280
317
def connection_params (self ):
281
318
"""Returns a dictionary with the connection parameters.
282
319
0 commit comments