Skip to content

Commit ed343dc

Browse files
committed
Parse rowset and tests
1 parent 462e3f9 commit ed343dc

8 files changed

Lines changed: 660 additions & 232 deletions

File tree

src/sqlitecloud/client.py

Lines changed: 90 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,25 @@
22
33
"""
44
from typing import Any, List, Optional
5+
from urllib import parse
56

67
from sqlitecloud.driver import Driver
7-
from sqlitecloud.types import SQCloudConfig, SQCloudConnect, SqliteCloudAccount
8+
from sqlitecloud.resultset import SqliteCloudResultSet
9+
from sqlitecloud.types import (
10+
SQCloudConfig,
11+
SQCloudConnect,
12+
SQCloudException,
13+
SqliteCloudAccount,
14+
)
815

916

1017
class SqliteCloudClient:
1118
"""
1219
Client to connect to SqliteCloud
1320
"""
1421

22+
SQLITE_DEFAULT_PORT = 8860
23+
1524
def __init__(
1625
self,
1726
cloud_account: Optional[SqliteCloudAccount] = None,
@@ -28,22 +37,15 @@ def __init__(
2837
2938
"""
3039
self.driver = Driver()
31-
32-
self.hostname: str = ''
33-
self.port: int = 8860
34-
40+
3541
self.config = SQCloudConfig()
3642

3743
# for pb in pub_subs:
3844
# self._pub_sub_cbs.append(("channel1", SQCloudPubSubCB(pb)))
3945
if connection_str:
40-
# TODO: parse connection string to create the config
41-
self.config = SQCloudConfig()
46+
self.config = self._parse_connection_string(connection_str)
4247
elif cloud_account:
4348
self.config.account = cloud_account
44-
self.hostname = cloud_account.hostname
45-
self.port = cloud_account.port
46-
4749
else:
4850
raise Exception("Missing connection parameters")
4951

@@ -56,7 +58,9 @@ def open_connection(self) -> SQCloudConnect:
5658
Raises:
5759
Exception: If an error occurs while opening the connection.
5860
"""
59-
connection = self.driver.connect(self.hostname, self.port, self.config)
61+
connection = self.driver.connect(
62+
self.config.account.hostname, self.config.account.port, self.config
63+
)
6064

6165
# SQCloudExec(connection, f"USE DATABASE {self.dbname};")
6266

@@ -75,9 +79,9 @@ def disconnect(self, conn: SQCloudConnect) -> None:
7579
"""
7680
self.driver.disconnect(conn)
7781

78-
# def exec_query(
79-
# self, query: str, conn: SQCloudConnect = None
80-
# ) -> SqliteCloudResultSet:
82+
def exec_query(
83+
self, query: str, conn: SQCloudConnect = None
84+
) -> SqliteCloudResultSet:
8185
"""Executes a SQL query on the SQLite database.
8286
8387
Args:
@@ -86,31 +90,82 @@ def disconnect(self, conn: SQCloudConnect) -> None:
8690
Returns:
8791
SqliteCloudResultSet: The result set of the executed query.
8892
"""
89-
# print(query)
90-
# # pylint: disable=unused-variable
91-
# local_conn, close_at_end = (
92-
# (conn, False) if conn else (self.open_connection(), True)
93-
# )
94-
# result: SQCloudResult = SQCloudExec(local_conn, self._encode_str_to_c(query))
95-
# self._check_connection(local_conn)
96-
# return SqliteCloudResultSet(result)
97-
# pass
93+
if not conn:
94+
conn = self.open_connection()
95+
96+
result = self.driver.execute(query, conn)
97+
return SqliteCloudResultSet(result)
9898

9999
# def exec_statement(
100100
# self, query: str, values: List[Any], conn: SQCloudConnect = None
101101
# ) -> SqliteCloudResultSet:
102-
# local_conn = conn if conn else self.open_connection()
103-
# result: SQCloudResult = SQCloudExecArray(
104-
# local_conn,
105-
# self._encode_str_to_c(query),
106-
# [SqlParameter(self._encode_str_to_c(str(v)), v) for v in values],
107-
# )
108-
# if SQCloudResultIsError(result):
109-
# raise Exception(
110-
# "Query error: " + str(SQCloudResultDump(local_conn, result))
111-
# )
112-
# return SqliteCloudResultSet(result)
113-
# pass
102+
# local_conn = conn if conn else self.open_connection()
103+
# result: SQCloudResult = SQCloudExecArray(
104+
# local_conn,
105+
# self._encode_str_to_c(query),
106+
# [SqlParameter(self._encode_str_to_c(str(v)), v) for v in values],
107+
# )
108+
# if SQCloudResultIsError(result):
109+
# raise Exception(
110+
# "Query error: " + str(SQCloudResultDump(local_conn, result))
111+
# )
112+
# return SqliteCloudResultSet(result)
113+
# pass
114114

115115
def sendblob(self):
116116
pass
117+
118+
def _parse_connection_string(self, connection_string) -> SQCloudConfig:
119+
# URL STRING FORMAT
120+
# sqlitecloud://user:pass@host.com:port/dbname?timeout=10&key2=value2&key3=value3
121+
# or sqlitecloud://host.sqlite.cloud:8860/dbname?apikey=zIiAARzKm9XBVllbAzkB1wqrgijJ3Gx0X5z1A4m4xBA
122+
123+
config = SQCloudConfig()
124+
config.account = SqliteCloudAccount()
125+
126+
try:
127+
params = parse.urlparse(connection_string)
128+
129+
options = {}
130+
query = params.query
131+
options = parse.parse_qs(query)
132+
for option, values in options.items():
133+
opt = option.lower()
134+
value = values.pop()
135+
136+
if value.lower() in ["true", "false"]:
137+
value = bool(value)
138+
elif value.isdigit():
139+
value = int(value)
140+
else:
141+
value = value
142+
143+
if hasattr(config, opt):
144+
setattr(config, opt, value)
145+
elif hasattr(config.account, opt):
146+
setattr(config.account, opt, value)
147+
148+
# apikey or username/password is accepted
149+
if not config.account.apikey:
150+
config.account.username = (
151+
parse.unquote(params.username) if params.username else ""
152+
)
153+
config.account.password = (
154+
parse.unquote(params.password) if params.password else ""
155+
)
156+
157+
path = params.path
158+
database = path.strip("/")
159+
if database:
160+
config.account.database = database
161+
162+
config.account.hostname = params.hostname
163+
config.account.port = (
164+
int(params.port) if params.port else self.SQLITE_DEFAULT_PORT
165+
)
166+
167+
return config
168+
except Exception as e:
169+
raise SQCloudException(
170+
f"Invalid connection string {connection_string}"
171+
) from e

0 commit comments

Comments
 (0)