kamau1 commited on
Commit
d4b70b5
·
verified ·
1 Parent(s): 98f6c3a

Upload 12 files

Browse files
Files changed (2) hide show
  1. app/utils/db_http.py +131 -140
  2. main.py +5 -1
app/utils/db_http.py CHANGED
@@ -5,9 +5,9 @@ This module provides functions for interacting with the Turso database using the
5
 
6
  import os
7
  import logging
8
- import requests
9
  import time
10
- from typing import List, Dict, Any, Optional, Tuple, Union
 
11
 
12
  # Configure logging
13
  logger = logging.getLogger("auth-server")
@@ -15,32 +15,32 @@ logger = logging.getLogger("auth-server")
15
  def get_http_url() -> Tuple[str, str]:
16
  """
17
  Get the HTTP URL and auth token for the Turso database.
18
-
19
  Returns:
20
  Tuple[str, str]: The HTTP URL and auth token.
21
  """
22
  # Extract the database URL and auth token
23
  db_url = os.getenv("TURSO_DATABASE_URL", "")
24
  auth_token = os.getenv("TURSO_AUTH_TOKEN", "")
25
-
26
  # Convert URL from libsql:// to https://
27
  if db_url.startswith("libsql://"):
28
  http_url = db_url.replace("libsql://", "https://")
29
  else:
30
  http_url = db_url
31
-
32
  # Ensure the URL doesn't have a trailing slash
33
  http_url = http_url.rstrip('/')
34
-
35
  return http_url, auth_token
36
 
37
  def get_headers(auth_token: str) -> Dict[str, str]:
38
  """
39
  Get the headers for the HTTP request.
40
-
41
  Args:
42
  auth_token (str): The authentication token.
43
-
44
  Returns:
45
  Dict[str, str]: The headers for the HTTP request.
46
  """
@@ -52,23 +52,24 @@ def get_headers(auth_token: str) -> Dict[str, str]:
52
  def execute_query(sql: str, params: List[Dict[str, Any]] = None, operation_id: str = None) -> Dict[str, Any]:
53
  """
54
  Execute a SQL query using the HTTP API.
55
-
56
  Args:
57
  sql (str): The SQL query to execute.
58
  params (List[Dict[str, Any]], optional): The parameters for the query. Defaults to None.
59
  operation_id (str, optional): A unique identifier for the operation. Defaults to None.
60
-
61
  Returns:
62
  Dict[str, Any]: The response from the database.
63
  """
64
  if operation_id is None:
65
  operation_id = f"query_{int(time.time())}"
66
-
67
- logger.info(f"[{operation_id}] Executing query: {sql}")
68
-
 
69
  http_url, auth_token = get_http_url()
70
  headers = get_headers(auth_token)
71
-
72
  # Prepare the query
73
  query = {
74
  "requests": [
@@ -82,48 +83,48 @@ def execute_query(sql: str, params: List[Dict[str, Any]] = None, operation_id: s
82
  {"type": "close"}
83
  ]
84
  }
85
-
86
  # Send the request
87
  try:
88
- response = requests.post(f"{http_url}/v2/pipeline", headers=headers, json=query)
89
  response.raise_for_status()
90
  result = response.json()
91
- logger.info(f"[{operation_id}] Query executed successfully")
92
  return result
93
  except Exception as e:
94
  logger.error(f"[{operation_id}] Error executing query: {str(e)}")
95
  raise
96
 
97
- def execute_pipeline(requests: List[Dict[str, Any]], operation_id: str = None) -> Dict[str, Any]:
98
  """
99
  Execute a pipeline of SQL queries using the HTTP API.
100
-
101
  Args:
102
- requests (List[Dict[str, Any]]): The requests to execute.
103
  operation_id (str, optional): A unique identifier for the operation. Defaults to None.
104
-
105
  Returns:
106
  Dict[str, Any]: The response from the database.
107
  """
108
  if operation_id is None:
109
  operation_id = f"pipeline_{int(time.time())}"
110
-
111
- logger.info(f"[{operation_id}] Executing pipeline with {len(requests)} requests")
112
-
113
  http_url, auth_token = get_http_url()
114
  headers = get_headers(auth_token)
115
-
116
  # Prepare the pipeline
117
  pipeline = {
118
- "requests": requests + [{"type": "close"}]
119
  }
120
-
121
  # Send the request
122
  try:
123
- response = requests.post(f"{http_url}/v2/pipeline", headers=headers, json=pipeline)
124
  response.raise_for_status()
125
  result = response.json()
126
- logger.info(f"[{operation_id}] Pipeline executed successfully")
127
  return result
128
  except Exception as e:
129
  logger.error(f"[{operation_id}] Error executing pipeline: {str(e)}")
@@ -132,25 +133,25 @@ def execute_pipeline(requests: List[Dict[str, Any]], operation_id: str = None) -
132
  def insert_record(table: str, data: Dict[str, Any], operation_id: str = None) -> Optional[int]:
133
  """
134
  Insert a record into a table.
135
-
136
  Args:
137
  table (str): The table to insert into.
138
  data (Dict[str, Any]): The data to insert.
139
  operation_id (str, optional): A unique identifier for the operation. Defaults to None.
140
-
141
  Returns:
142
  Optional[int]: The ID of the inserted record, or None if the insert failed.
143
  """
144
  if operation_id is None:
145
  operation_id = f"insert_{int(time.time())}"
146
-
147
- logger.info(f"[{operation_id}] Inserting record into {table}")
148
-
149
  # Prepare the SQL and parameters
150
  columns = list(data.keys())
151
  placeholders = ["?"] * len(columns)
152
  sql = f"INSERT INTO {table} ({', '.join(columns)}) VALUES ({', '.join(placeholders)})"
153
-
154
  params = []
155
  for key, value in data.items():
156
  if isinstance(value, str):
@@ -163,42 +164,32 @@ def insert_record(table: str, data: Dict[str, Any], operation_id: str = None) ->
163
  params.append({"type": "null", "value": None})
164
  else:
165
  params.append({"type": "text", "value": str(value)})
166
-
167
- # Execute the pipeline with insert and get last ID
168
- pipeline_requests = [
169
- {
170
- "type": "execute",
171
- "stmt": {
172
- "sql": sql,
173
- "args": params
174
- }
175
- },
176
- {
177
- "type": "execute",
178
- "stmt": {"sql": "SELECT last_insert_rowid()"}
179
- }
180
- ]
181
-
182
  try:
183
- result = execute_pipeline(pipeline_requests, operation_id)
184
-
185
- # Check for errors in the first request (insert)
 
186
  if "results" in result and len(result["results"]) > 0:
187
  if result["results"][0]["type"] == "error":
188
  error_msg = result["results"][0]["error"]["message"]
189
  logger.error(f"[{operation_id}] Insert error: {error_msg}")
190
  return None
191
-
192
- # Try to get the last inserted ID
 
 
193
  last_id = None
194
- if "results" in result and len(result["results"]) > 1:
195
- if result["results"][1]["type"] == "ok":
196
- rows = result["results"][1]["response"]["result"]["rows"]
197
  if rows and len(rows) > 0:
198
  last_id = int(rows[0][0]["value"])
199
  logger.info(f"[{operation_id}] Record inserted with ID: {last_id}")
200
  return last_id
201
-
 
202
  logger.warning(f"[{operation_id}] Insert succeeded but couldn't get ID")
203
  return None
204
  except Exception as e:
@@ -208,26 +199,26 @@ def insert_record(table: str, data: Dict[str, Any], operation_id: str = None) ->
208
  def update_record(table: str, data: Dict[str, Any], condition: str, condition_params: List[Dict[str, Any]], operation_id: str = None) -> bool:
209
  """
210
  Update a record in a table.
211
-
212
  Args:
213
  table (str): The table to update.
214
  data (Dict[str, Any]): The data to update.
215
  condition (str): The condition for the update (e.g., "id = ?").
216
  condition_params (List[Dict[str, Any]]): The parameters for the condition.
217
  operation_id (str, optional): A unique identifier for the operation. Defaults to None.
218
-
219
  Returns:
220
  bool: True if the update succeeded, False otherwise.
221
  """
222
  if operation_id is None:
223
  operation_id = f"update_{int(time.time())}"
224
-
225
- logger.info(f"[{operation_id}] Updating record in {table}")
226
-
227
  # Prepare the SQL and parameters
228
  set_clauses = [f"{key} = ?" for key in data.keys()]
229
  sql = f"UPDATE {table} SET {', '.join(set_clauses)} WHERE {condition}"
230
-
231
  params = []
232
  for key, value in data.items():
233
  if isinstance(value, str):
@@ -240,25 +231,25 @@ def update_record(table: str, data: Dict[str, Any], condition: str, condition_pa
240
  params.append({"type": "null", "value": None})
241
  else:
242
  params.append({"type": "text", "value": str(value)})
243
-
244
  # Add condition parameters
245
  params.extend(condition_params)
246
-
247
  try:
248
  result = execute_query(sql, params, operation_id)
249
-
250
  # Check for errors
251
  if "results" in result and len(result["results"]) > 0:
252
  if result["results"][0]["type"] == "error":
253
  error_msg = result["results"][0]["error"]["message"]
254
  logger.error(f"[{operation_id}] Update error: {error_msg}")
255
  return False
256
-
257
  # Check affected rows
258
  affected_rows = result["results"][0]["response"]["result"]["affected_row_count"]
259
- logger.info(f"[{operation_id}] Updated {affected_rows} rows")
260
  return affected_rows > 0
261
-
262
  return False
263
  except Exception as e:
264
  logger.error(f"[{operation_id}] Error updating record: {str(e)}")
@@ -267,50 +258,50 @@ def update_record(table: str, data: Dict[str, Any], condition: str, condition_pa
267
  def delete_record(table: str, condition: str, condition_params: List[Dict[str, Any]], operation_id: str = None) -> bool:
268
  """
269
  Delete a record from a table.
270
-
271
  Args:
272
  table (str): The table to delete from.
273
  condition (str): The condition for the delete (e.g., "id = ?").
274
  condition_params (List[Dict[str, Any]]): The parameters for the condition.
275
  operation_id (str, optional): A unique identifier for the operation. Defaults to None.
276
-
277
  Returns:
278
  bool: True if the delete succeeded, False otherwise.
279
  """
280
  if operation_id is None:
281
  operation_id = f"delete_{int(time.time())}"
282
-
283
  logger.info(f"[{operation_id}] Deleting record from {table}")
284
-
285
  # Prepare the SQL
286
  sql = f"DELETE FROM {table} WHERE {condition}"
287
-
288
  try:
289
  result = execute_query(sql, condition_params, operation_id)
290
-
291
  # Check for errors
292
  if "results" in result and len(result["results"]) > 0:
293
  if result["results"][0]["type"] == "error":
294
  error_msg = result["results"][0]["error"]["message"]
295
  logger.error(f"[{operation_id}] Delete error: {error_msg}")
296
  return False
297
-
298
  # Check affected rows
299
  affected_rows = result["results"][0]["response"]["result"]["affected_row_count"]
300
  logger.info(f"[{operation_id}] Deleted {affected_rows} rows")
301
  return affected_rows > 0
302
-
303
  return False
304
  except Exception as e:
305
  logger.error(f"[{operation_id}] Error deleting record: {str(e)}")
306
  return False
307
 
308
- def select_records(table: str, columns: List[str] = None, condition: str = None,
309
- condition_params: List[Dict[str, Any]] = None, limit: int = None,
310
  offset: int = None, order_by: str = None, operation_id: str = None) -> List[Dict[str, Any]]:
311
  """
312
  Select records from a table.
313
-
314
  Args:
315
  table (str): The table to select from.
316
  columns (List[str], optional): The columns to select. Defaults to None (all columns).
@@ -320,47 +311,47 @@ def select_records(table: str, columns: List[str] = None, condition: str = None,
320
  offset (int, optional): The number of records to skip. Defaults to None.
321
  order_by (str, optional): The order by clause. Defaults to None.
322
  operation_id (str, optional): A unique identifier for the operation. Defaults to None.
323
-
324
  Returns:
325
  List[Dict[str, Any]]: The selected records.
326
  """
327
  if operation_id is None:
328
  operation_id = f"select_{int(time.time())}"
329
-
330
- logger.info(f"[{operation_id}] Selecting records from {table}")
331
-
332
  # Prepare the SQL
333
  cols = "*" if not columns else ", ".join(columns)
334
  sql = f"SELECT {cols} FROM {table}"
335
-
336
  if condition:
337
  sql += f" WHERE {condition}"
338
-
339
  if order_by:
340
  sql += f" ORDER BY {order_by}"
341
-
342
  if limit:
343
  sql += f" LIMIT {limit}"
344
-
345
  if offset:
346
  sql += f" OFFSET {offset}"
347
-
348
  try:
349
  result = execute_query(sql, condition_params, operation_id)
350
-
351
  # Check for errors
352
  if "results" in result and len(result["results"]) > 0:
353
  if result["results"][0]["type"] == "error":
354
  error_msg = result["results"][0]["error"]["message"]
355
  logger.error(f"[{operation_id}] Select error: {error_msg}")
356
  return []
357
-
358
  # Extract the records
359
  response = result["results"][0]["response"]
360
  if "result" in response and "rows" in response["result"]:
361
  rows = response["result"]["rows"]
362
  cols = response["result"]["cols"]
363
-
364
  # Convert rows to dictionaries
365
  records = []
366
  for row in rows:
@@ -368,7 +359,7 @@ def select_records(table: str, columns: List[str] = None, condition: str = None,
368
  for i, col in enumerate(cols):
369
  col_name = col["name"]
370
  value = row[i]["value"]
371
-
372
  # Convert value based on type
373
  if row[i]["type"] == "integer":
374
  value = int(value)
@@ -376,15 +367,15 @@ def select_records(table: str, columns: List[str] = None, condition: str = None,
376
  value = float(value)
377
  elif row[i]["type"] == "null":
378
  value = None
379
-
380
  record[col_name] = value
381
-
382
  records.append(record)
383
-
384
- logger.info(f"[{operation_id}] Selected {len(records)} records")
385
  return records
386
-
387
- logger.warning(f"[{operation_id}] No records found")
388
  return []
389
  except Exception as e:
390
  logger.error(f"[{operation_id}] Error selecting records: {str(e)}")
@@ -393,70 +384,70 @@ def select_records(table: str, columns: List[str] = None, condition: str = None,
393
  def get_record_by_id(table: str, id: int, columns: List[str] = None, operation_id: str = None) -> Optional[Dict[str, Any]]:
394
  """
395
  Get a record by ID.
396
-
397
  Args:
398
  table (str): The table to select from.
399
  id (int): The ID of the record.
400
  columns (List[str], optional): The columns to select. Defaults to None (all columns).
401
  operation_id (str, optional): A unique identifier for the operation. Defaults to None.
402
-
403
  Returns:
404
  Optional[Dict[str, Any]]: The record, or None if not found.
405
  """
406
  if operation_id is None:
407
  operation_id = f"get_by_id_{int(time.time())}"
408
-
409
  condition = "id = ?"
410
  condition_params = [{"type": "integer", "value": str(id)}]
411
-
412
  records = select_records(table, columns, condition, condition_params, limit=1, operation_id=operation_id)
413
-
414
  if records:
415
  return records[0]
416
-
417
  return None
418
 
419
  def count_records(table: str, condition: str = None, condition_params: List[Dict[str, Any]] = None, operation_id: str = None) -> int:
420
  """
421
  Count records in a table.
422
-
423
  Args:
424
  table (str): The table to count records in.
425
  condition (str, optional): The condition for the count. Defaults to None.
426
  condition_params (List[Dict[str, Any]], optional): The parameters for the condition. Defaults to None.
427
  operation_id (str, optional): A unique identifier for the operation. Defaults to None.
428
-
429
  Returns:
430
  int: The number of records.
431
  """
432
  if operation_id is None:
433
  operation_id = f"count_{int(time.time())}"
434
-
435
  logger.info(f"[{operation_id}] Counting records in {table}")
436
-
437
  # Prepare the SQL
438
  sql = f"SELECT COUNT(*) FROM {table}"
439
-
440
  if condition:
441
  sql += f" WHERE {condition}"
442
-
443
  try:
444
  result = execute_query(sql, condition_params, operation_id)
445
-
446
  # Check for errors
447
  if "results" in result and len(result["results"]) > 0:
448
  if result["results"][0]["type"] == "error":
449
  error_msg = result["results"][0]["error"]["message"]
450
  logger.error(f"[{operation_id}] Count error: {error_msg}")
451
  return 0
452
-
453
  # Extract the count
454
  response = result["results"][0]["response"]
455
  if "result" in response and "rows" in response["result"] and response["result"]["rows"]:
456
  count = int(response["result"]["rows"][0][0]["value"])
457
  logger.info(f"[{operation_id}] Counted {count} records")
458
  return count
459
-
460
  logger.warning(f"[{operation_id}] Count failed")
461
  return 0
462
  except Exception as e:
@@ -466,13 +457,13 @@ def count_records(table: str, condition: str = None, condition_params: List[Dict
466
  def record_exists(table: str, condition: str, condition_params: List[Dict[str, Any]], operation_id: str = None) -> bool:
467
  """
468
  Check if a record exists in a table.
469
-
470
  Args:
471
  table (str): The table to check.
472
  condition (str): The condition for the check.
473
  condition_params (List[Dict[str, Any]]): The parameters for the condition.
474
  operation_id (str, optional): A unique identifier for the operation. Defaults to None.
475
-
476
  Returns:
477
  bool: True if the record exists, False otherwise.
478
  """
@@ -482,36 +473,36 @@ def record_exists(table: str, condition: str, condition_params: List[Dict[str, A
482
  def create_table_if_not_exists(table: str, schema: str, operation_id: str = None) -> bool:
483
  """
484
  Create a table if it doesn't exist.
485
-
486
  Args:
487
  table (str): The table to create.
488
  schema (str): The schema for the table.
489
  operation_id (str, optional): A unique identifier for the operation. Defaults to None.
490
-
491
  Returns:
492
  bool: True if the table was created or already exists, False otherwise.
493
  """
494
  if operation_id is None:
495
  operation_id = f"create_table_{int(time.time())}"
496
-
497
  logger.info(f"[{operation_id}] Creating table {table} if not exists")
498
-
499
  # Prepare the SQL
500
  sql = f"CREATE TABLE IF NOT EXISTS {table} ({schema})"
501
-
502
  try:
503
  result = execute_query(sql, operation_id=operation_id)
504
-
505
  # Check for errors
506
  if "results" in result and len(result["results"]) > 0:
507
  if result["results"][0]["type"] == "error":
508
  error_msg = result["results"][0]["error"]["message"]
509
  logger.error(f"[{operation_id}] Create table error: {error_msg}")
510
  return False
511
-
512
  logger.info(f"[{operation_id}] Table {table} created or already exists")
513
  return True
514
-
515
  return False
516
  except Exception as e:
517
  logger.error(f"[{operation_id}] Error creating table: {str(e)}")
@@ -520,22 +511,22 @@ def create_table_if_not_exists(table: str, schema: str, operation_id: str = None
520
  def execute_transaction(queries: List[Tuple[str, List[Dict[str, Any]]]], operation_id: str = None) -> bool:
521
  """
522
  Execute a transaction with multiple queries.
523
-
524
  Args:
525
  queries (List[Tuple[str, List[Dict[str, Any]]]]): The queries to execute.
526
  operation_id (str, optional): A unique identifier for the operation. Defaults to None.
527
-
528
  Returns:
529
  bool: True if the transaction succeeded, False otherwise.
530
  """
531
  if operation_id is None:
532
  operation_id = f"transaction_{int(time.time())}"
533
-
534
  logger.info(f"[{operation_id}] Executing transaction with {len(queries)} queries")
535
-
536
  # Prepare the pipeline
537
  requests = [{"type": "execute", "stmt": {"sql": "BEGIN"}}]
538
-
539
  for sql, params in queries:
540
  requests.append({
541
  "type": "execute",
@@ -544,35 +535,35 @@ def execute_transaction(queries: List[Tuple[str, List[Dict[str, Any]]]], operati
544
  "args": params or []
545
  }
546
  })
547
-
548
  requests.append({"type": "execute", "stmt": {"sql": "COMMIT"}})
549
-
550
  try:
551
  result = execute_pipeline(requests, operation_id)
552
-
553
  # Check for errors
554
  for i, res in enumerate(result.get("results", [])):
555
  if res.get("type") == "error":
556
  error_msg = res.get("error", {}).get("message", "Unknown error")
557
  logger.error(f"[{operation_id}] Transaction error in query {i}: {error_msg}")
558
-
559
  # Try to rollback
560
  try:
561
  execute_query("ROLLBACK", operation_id=f"{operation_id}_rollback")
562
  except:
563
  pass
564
-
565
  return False
566
-
567
  logger.info(f"[{operation_id}] Transaction executed successfully")
568
  return True
569
  except Exception as e:
570
  logger.error(f"[{operation_id}] Error executing transaction: {str(e)}")
571
-
572
  # Try to rollback
573
  try:
574
  execute_query("ROLLBACK", operation_id=f"{operation_id}_rollback")
575
  except:
576
  pass
577
-
578
  return False
 
5
 
6
  import os
7
  import logging
 
8
  import time
9
+ import requests as req
10
+ from typing import List, Dict, Any, Optional, Tuple
11
 
12
  # Configure logging
13
  logger = logging.getLogger("auth-server")
 
15
  def get_http_url() -> Tuple[str, str]:
16
  """
17
  Get the HTTP URL and auth token for the Turso database.
18
+
19
  Returns:
20
  Tuple[str, str]: The HTTP URL and auth token.
21
  """
22
  # Extract the database URL and auth token
23
  db_url = os.getenv("TURSO_DATABASE_URL", "")
24
  auth_token = os.getenv("TURSO_AUTH_TOKEN", "")
25
+
26
  # Convert URL from libsql:// to https://
27
  if db_url.startswith("libsql://"):
28
  http_url = db_url.replace("libsql://", "https://")
29
  else:
30
  http_url = db_url
31
+
32
  # Ensure the URL doesn't have a trailing slash
33
  http_url = http_url.rstrip('/')
34
+
35
  return http_url, auth_token
36
 
37
  def get_headers(auth_token: str) -> Dict[str, str]:
38
  """
39
  Get the headers for the HTTP request.
40
+
41
  Args:
42
  auth_token (str): The authentication token.
43
+
44
  Returns:
45
  Dict[str, str]: The headers for the HTTP request.
46
  """
 
52
  def execute_query(sql: str, params: List[Dict[str, Any]] = None, operation_id: str = None) -> Dict[str, Any]:
53
  """
54
  Execute a SQL query using the HTTP API.
55
+
56
  Args:
57
  sql (str): The SQL query to execute.
58
  params (List[Dict[str, Any]], optional): The parameters for the query. Defaults to None.
59
  operation_id (str, optional): A unique identifier for the operation. Defaults to None.
60
+
61
  Returns:
62
  Dict[str, Any]: The response from the database.
63
  """
64
  if operation_id is None:
65
  operation_id = f"query_{int(time.time())}"
66
+
67
+ # Only log at debug level for routine operations
68
+ logger.debug(f"[{operation_id}] Executing query: {sql}")
69
+
70
  http_url, auth_token = get_http_url()
71
  headers = get_headers(auth_token)
72
+
73
  # Prepare the query
74
  query = {
75
  "requests": [
 
83
  {"type": "close"}
84
  ]
85
  }
86
+
87
  # Send the request
88
  try:
89
+ response = req.post(f"{http_url}/v2/pipeline", headers=headers, json=query)
90
  response.raise_for_status()
91
  result = response.json()
92
+ logger.debug(f"[{operation_id}] Query executed successfully")
93
  return result
94
  except Exception as e:
95
  logger.error(f"[{operation_id}] Error executing query: {str(e)}")
96
  raise
97
 
98
+ def execute_pipeline(pipeline_requests: List[Dict[str, Any]], operation_id: str = None) -> Dict[str, Any]:
99
  """
100
  Execute a pipeline of SQL queries using the HTTP API.
101
+
102
  Args:
103
+ pipeline_requests (List[Dict[str, Any]]): The requests to execute.
104
  operation_id (str, optional): A unique identifier for the operation. Defaults to None.
105
+
106
  Returns:
107
  Dict[str, Any]: The response from the database.
108
  """
109
  if operation_id is None:
110
  operation_id = f"pipeline_{int(time.time())}"
111
+
112
+ logger.debug(f"[{operation_id}] Executing pipeline with {len(pipeline_requests)} requests")
113
+
114
  http_url, auth_token = get_http_url()
115
  headers = get_headers(auth_token)
116
+
117
  # Prepare the pipeline
118
  pipeline = {
119
+ "requests": pipeline_requests + [{"type": "close"}]
120
  }
121
+
122
  # Send the request
123
  try:
124
+ response = req.post(f"{http_url}/v2/pipeline", headers=headers, json=pipeline)
125
  response.raise_for_status()
126
  result = response.json()
127
+ logger.debug(f"[{operation_id}] Pipeline executed successfully")
128
  return result
129
  except Exception as e:
130
  logger.error(f"[{operation_id}] Error executing pipeline: {str(e)}")
 
133
  def insert_record(table: str, data: Dict[str, Any], operation_id: str = None) -> Optional[int]:
134
  """
135
  Insert a record into a table.
136
+
137
  Args:
138
  table (str): The table to insert into.
139
  data (Dict[str, Any]): The data to insert.
140
  operation_id (str, optional): A unique identifier for the operation. Defaults to None.
141
+
142
  Returns:
143
  Optional[int]: The ID of the inserted record, or None if the insert failed.
144
  """
145
  if operation_id is None:
146
  operation_id = f"insert_{int(time.time())}"
147
+
148
+ logger.debug(f"[{operation_id}] Inserting record into {table}")
149
+
150
  # Prepare the SQL and parameters
151
  columns = list(data.keys())
152
  placeholders = ["?"] * len(columns)
153
  sql = f"INSERT INTO {table} ({', '.join(columns)}) VALUES ({', '.join(placeholders)})"
154
+
155
  params = []
156
  for key, value in data.items():
157
  if isinstance(value, str):
 
164
  params.append({"type": "null", "value": None})
165
  else:
166
  params.append({"type": "text", "value": str(value)})
167
+
168
+ # Execute the query directly instead of using pipeline
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  try:
170
+ # Direct query execution is more reliable
171
+ result = execute_query(sql, params, operation_id)
172
+
173
+ # Check for errors
174
  if "results" in result and len(result["results"]) > 0:
175
  if result["results"][0]["type"] == "error":
176
  error_msg = result["results"][0]["error"]["message"]
177
  logger.error(f"[{operation_id}] Insert error: {error_msg}")
178
  return None
179
+
180
+ # Try to get the last inserted ID with a separate query
181
+ id_result = execute_query("SELECT last_insert_rowid()", operation_id=f"{operation_id}_get_id")
182
+
183
  last_id = None
184
+ if "results" in id_result and len(id_result["results"]) > 0:
185
+ if id_result["results"][0]["type"] == "ok":
186
+ rows = id_result["results"][0]["response"]["result"]["rows"]
187
  if rows and len(rows) > 0:
188
  last_id = int(rows[0][0]["value"])
189
  logger.info(f"[{operation_id}] Record inserted with ID: {last_id}")
190
  return last_id
191
+
192
+ # If we can't get the ID, try to find it by other means
193
  logger.warning(f"[{operation_id}] Insert succeeded but couldn't get ID")
194
  return None
195
  except Exception as e:
 
199
  def update_record(table: str, data: Dict[str, Any], condition: str, condition_params: List[Dict[str, Any]], operation_id: str = None) -> bool:
200
  """
201
  Update a record in a table.
202
+
203
  Args:
204
  table (str): The table to update.
205
  data (Dict[str, Any]): The data to update.
206
  condition (str): The condition for the update (e.g., "id = ?").
207
  condition_params (List[Dict[str, Any]]): The parameters for the condition.
208
  operation_id (str, optional): A unique identifier for the operation. Defaults to None.
209
+
210
  Returns:
211
  bool: True if the update succeeded, False otherwise.
212
  """
213
  if operation_id is None:
214
  operation_id = f"update_{int(time.time())}"
215
+
216
+ logger.debug(f"[{operation_id}] Updating record in {table}")
217
+
218
  # Prepare the SQL and parameters
219
  set_clauses = [f"{key} = ?" for key in data.keys()]
220
  sql = f"UPDATE {table} SET {', '.join(set_clauses)} WHERE {condition}"
221
+
222
  params = []
223
  for key, value in data.items():
224
  if isinstance(value, str):
 
231
  params.append({"type": "null", "value": None})
232
  else:
233
  params.append({"type": "text", "value": str(value)})
234
+
235
  # Add condition parameters
236
  params.extend(condition_params)
237
+
238
  try:
239
  result = execute_query(sql, params, operation_id)
240
+
241
  # Check for errors
242
  if "results" in result and len(result["results"]) > 0:
243
  if result["results"][0]["type"] == "error":
244
  error_msg = result["results"][0]["error"]["message"]
245
  logger.error(f"[{operation_id}] Update error: {error_msg}")
246
  return False
247
+
248
  # Check affected rows
249
  affected_rows = result["results"][0]["response"]["result"]["affected_row_count"]
250
+ logger.debug(f"[{operation_id}] Updated {affected_rows} rows")
251
  return affected_rows > 0
252
+
253
  return False
254
  except Exception as e:
255
  logger.error(f"[{operation_id}] Error updating record: {str(e)}")
 
258
  def delete_record(table: str, condition: str, condition_params: List[Dict[str, Any]], operation_id: str = None) -> bool:
259
  """
260
  Delete a record from a table.
261
+
262
  Args:
263
  table (str): The table to delete from.
264
  condition (str): The condition for the delete (e.g., "id = ?").
265
  condition_params (List[Dict[str, Any]]): The parameters for the condition.
266
  operation_id (str, optional): A unique identifier for the operation. Defaults to None.
267
+
268
  Returns:
269
  bool: True if the delete succeeded, False otherwise.
270
  """
271
  if operation_id is None:
272
  operation_id = f"delete_{int(time.time())}"
273
+
274
  logger.info(f"[{operation_id}] Deleting record from {table}")
275
+
276
  # Prepare the SQL
277
  sql = f"DELETE FROM {table} WHERE {condition}"
278
+
279
  try:
280
  result = execute_query(sql, condition_params, operation_id)
281
+
282
  # Check for errors
283
  if "results" in result and len(result["results"]) > 0:
284
  if result["results"][0]["type"] == "error":
285
  error_msg = result["results"][0]["error"]["message"]
286
  logger.error(f"[{operation_id}] Delete error: {error_msg}")
287
  return False
288
+
289
  # Check affected rows
290
  affected_rows = result["results"][0]["response"]["result"]["affected_row_count"]
291
  logger.info(f"[{operation_id}] Deleted {affected_rows} rows")
292
  return affected_rows > 0
293
+
294
  return False
295
  except Exception as e:
296
  logger.error(f"[{operation_id}] Error deleting record: {str(e)}")
297
  return False
298
 
299
+ def select_records(table: str, columns: List[str] = None, condition: str = None,
300
+ condition_params: List[Dict[str, Any]] = None, limit: int = None,
301
  offset: int = None, order_by: str = None, operation_id: str = None) -> List[Dict[str, Any]]:
302
  """
303
  Select records from a table.
304
+
305
  Args:
306
  table (str): The table to select from.
307
  columns (List[str], optional): The columns to select. Defaults to None (all columns).
 
311
  offset (int, optional): The number of records to skip. Defaults to None.
312
  order_by (str, optional): The order by clause. Defaults to None.
313
  operation_id (str, optional): A unique identifier for the operation. Defaults to None.
314
+
315
  Returns:
316
  List[Dict[str, Any]]: The selected records.
317
  """
318
  if operation_id is None:
319
  operation_id = f"select_{int(time.time())}"
320
+
321
+ logger.debug(f"[{operation_id}] Selecting records from {table}")
322
+
323
  # Prepare the SQL
324
  cols = "*" if not columns else ", ".join(columns)
325
  sql = f"SELECT {cols} FROM {table}"
326
+
327
  if condition:
328
  sql += f" WHERE {condition}"
329
+
330
  if order_by:
331
  sql += f" ORDER BY {order_by}"
332
+
333
  if limit:
334
  sql += f" LIMIT {limit}"
335
+
336
  if offset:
337
  sql += f" OFFSET {offset}"
338
+
339
  try:
340
  result = execute_query(sql, condition_params, operation_id)
341
+
342
  # Check for errors
343
  if "results" in result and len(result["results"]) > 0:
344
  if result["results"][0]["type"] == "error":
345
  error_msg = result["results"][0]["error"]["message"]
346
  logger.error(f"[{operation_id}] Select error: {error_msg}")
347
  return []
348
+
349
  # Extract the records
350
  response = result["results"][0]["response"]
351
  if "result" in response and "rows" in response["result"]:
352
  rows = response["result"]["rows"]
353
  cols = response["result"]["cols"]
354
+
355
  # Convert rows to dictionaries
356
  records = []
357
  for row in rows:
 
359
  for i, col in enumerate(cols):
360
  col_name = col["name"]
361
  value = row[i]["value"]
362
+
363
  # Convert value based on type
364
  if row[i]["type"] == "integer":
365
  value = int(value)
 
367
  value = float(value)
368
  elif row[i]["type"] == "null":
369
  value = None
370
+
371
  record[col_name] = value
372
+
373
  records.append(record)
374
+
375
+ logger.debug(f"[{operation_id}] Selected {len(records)} records")
376
  return records
377
+
378
+ logger.debug(f"[{operation_id}] No records found")
379
  return []
380
  except Exception as e:
381
  logger.error(f"[{operation_id}] Error selecting records: {str(e)}")
 
384
  def get_record_by_id(table: str, id: int, columns: List[str] = None, operation_id: str = None) -> Optional[Dict[str, Any]]:
385
  """
386
  Get a record by ID.
387
+
388
  Args:
389
  table (str): The table to select from.
390
  id (int): The ID of the record.
391
  columns (List[str], optional): The columns to select. Defaults to None (all columns).
392
  operation_id (str, optional): A unique identifier for the operation. Defaults to None.
393
+
394
  Returns:
395
  Optional[Dict[str, Any]]: The record, or None if not found.
396
  """
397
  if operation_id is None:
398
  operation_id = f"get_by_id_{int(time.time())}"
399
+
400
  condition = "id = ?"
401
  condition_params = [{"type": "integer", "value": str(id)}]
402
+
403
  records = select_records(table, columns, condition, condition_params, limit=1, operation_id=operation_id)
404
+
405
  if records:
406
  return records[0]
407
+
408
  return None
409
 
410
  def count_records(table: str, condition: str = None, condition_params: List[Dict[str, Any]] = None, operation_id: str = None) -> int:
411
  """
412
  Count records in a table.
413
+
414
  Args:
415
  table (str): The table to count records in.
416
  condition (str, optional): The condition for the count. Defaults to None.
417
  condition_params (List[Dict[str, Any]], optional): The parameters for the condition. Defaults to None.
418
  operation_id (str, optional): A unique identifier for the operation. Defaults to None.
419
+
420
  Returns:
421
  int: The number of records.
422
  """
423
  if operation_id is None:
424
  operation_id = f"count_{int(time.time())}"
425
+
426
  logger.info(f"[{operation_id}] Counting records in {table}")
427
+
428
  # Prepare the SQL
429
  sql = f"SELECT COUNT(*) FROM {table}"
430
+
431
  if condition:
432
  sql += f" WHERE {condition}"
433
+
434
  try:
435
  result = execute_query(sql, condition_params, operation_id)
436
+
437
  # Check for errors
438
  if "results" in result and len(result["results"]) > 0:
439
  if result["results"][0]["type"] == "error":
440
  error_msg = result["results"][0]["error"]["message"]
441
  logger.error(f"[{operation_id}] Count error: {error_msg}")
442
  return 0
443
+
444
  # Extract the count
445
  response = result["results"][0]["response"]
446
  if "result" in response and "rows" in response["result"] and response["result"]["rows"]:
447
  count = int(response["result"]["rows"][0][0]["value"])
448
  logger.info(f"[{operation_id}] Counted {count} records")
449
  return count
450
+
451
  logger.warning(f"[{operation_id}] Count failed")
452
  return 0
453
  except Exception as e:
 
457
  def record_exists(table: str, condition: str, condition_params: List[Dict[str, Any]], operation_id: str = None) -> bool:
458
  """
459
  Check if a record exists in a table.
460
+
461
  Args:
462
  table (str): The table to check.
463
  condition (str): The condition for the check.
464
  condition_params (List[Dict[str, Any]]): The parameters for the condition.
465
  operation_id (str, optional): A unique identifier for the operation. Defaults to None.
466
+
467
  Returns:
468
  bool: True if the record exists, False otherwise.
469
  """
 
473
  def create_table_if_not_exists(table: str, schema: str, operation_id: str = None) -> bool:
474
  """
475
  Create a table if it doesn't exist.
476
+
477
  Args:
478
  table (str): The table to create.
479
  schema (str): The schema for the table.
480
  operation_id (str, optional): A unique identifier for the operation. Defaults to None.
481
+
482
  Returns:
483
  bool: True if the table was created or already exists, False otherwise.
484
  """
485
  if operation_id is None:
486
  operation_id = f"create_table_{int(time.time())}"
487
+
488
  logger.info(f"[{operation_id}] Creating table {table} if not exists")
489
+
490
  # Prepare the SQL
491
  sql = f"CREATE TABLE IF NOT EXISTS {table} ({schema})"
492
+
493
  try:
494
  result = execute_query(sql, operation_id=operation_id)
495
+
496
  # Check for errors
497
  if "results" in result and len(result["results"]) > 0:
498
  if result["results"][0]["type"] == "error":
499
  error_msg = result["results"][0]["error"]["message"]
500
  logger.error(f"[{operation_id}] Create table error: {error_msg}")
501
  return False
502
+
503
  logger.info(f"[{operation_id}] Table {table} created or already exists")
504
  return True
505
+
506
  return False
507
  except Exception as e:
508
  logger.error(f"[{operation_id}] Error creating table: {str(e)}")
 
511
  def execute_transaction(queries: List[Tuple[str, List[Dict[str, Any]]]], operation_id: str = None) -> bool:
512
  """
513
  Execute a transaction with multiple queries.
514
+
515
  Args:
516
  queries (List[Tuple[str, List[Dict[str, Any]]]]): The queries to execute.
517
  operation_id (str, optional): A unique identifier for the operation. Defaults to None.
518
+
519
  Returns:
520
  bool: True if the transaction succeeded, False otherwise.
521
  """
522
  if operation_id is None:
523
  operation_id = f"transaction_{int(time.time())}"
524
+
525
  logger.info(f"[{operation_id}] Executing transaction with {len(queries)} queries")
526
+
527
  # Prepare the pipeline
528
  requests = [{"type": "execute", "stmt": {"sql": "BEGIN"}}]
529
+
530
  for sql, params in queries:
531
  requests.append({
532
  "type": "execute",
 
535
  "args": params or []
536
  }
537
  })
538
+
539
  requests.append({"type": "execute", "stmt": {"sql": "COMMIT"}})
540
+
541
  try:
542
  result = execute_pipeline(requests, operation_id)
543
+
544
  # Check for errors
545
  for i, res in enumerate(result.get("results", [])):
546
  if res.get("type") == "error":
547
  error_msg = res.get("error", {}).get("message", "Unknown error")
548
  logger.error(f"[{operation_id}] Transaction error in query {i}: {error_msg}")
549
+
550
  # Try to rollback
551
  try:
552
  execute_query("ROLLBACK", operation_id=f"{operation_id}_rollback")
553
  except:
554
  pass
555
+
556
  return False
557
+
558
  logger.info(f"[{operation_id}] Transaction executed successfully")
559
  return True
560
  except Exception as e:
561
  logger.error(f"[{operation_id}] Error executing transaction: {str(e)}")
562
+
563
  # Try to rollback
564
  try:
565
  execute_query("ROLLBACK", operation_id=f"{operation_id}_rollback")
566
  except:
567
  pass
568
+
569
  return False
main.py CHANGED
@@ -19,12 +19,16 @@ from app.utils import db_http
19
 
20
  # Configure logging
21
  logging.basicConfig(
22
- level=logging.INFO,
23
  format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
24
  handlers=[logging.StreamHandler(sys.stdout)]
25
  )
26
  logger = logging.getLogger("auth-server")
27
 
 
 
 
 
28
  # Import database libraries
29
  try:
30
  # First try the recommended libsql-experimental package
 
19
 
20
  # Configure logging
21
  logging.basicConfig(
22
+ level=logging.WARNING, # Changed from INFO to WARNING to reduce verbosity
23
  format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
24
  handlers=[logging.StreamHandler(sys.stdout)]
25
  )
26
  logger = logging.getLogger("auth-server")
27
 
28
+ # Set specific loggers to different levels as needed
29
+ logging.getLogger("uvicorn").setLevel(logging.WARNING)
30
+ logging.getLogger("fastapi").setLevel(logging.WARNING)
31
+
32
  # Import database libraries
33
  try:
34
  # First try the recommended libsql-experimental package