|
1 | 1 | import os |
| 2 | +import json |
2 | 3 | import string |
3 | 4 | import logging |
4 | 5 | from typing import List, Dict, Any, Optional, Tuple |
@@ -328,6 +329,52 @@ def execute_many(self, command: str, params_list: List[Dict[str, Any]]) -> int: |
328 | 329 | logger.error(f'Batch execution error: {e}') |
329 | 330 | raise |
330 | 331 |
|
| 332 | + def insert_rows_json(self, table_name: str, data: List[Dict[str, Any]]) -> int: |
| 333 | + """ |
| 334 | + Insert rows provided as a list of dictionaries into a table. |
| 335 | +
|
| 336 | + Dict/list values are serialized to JSON strings so they can be stored |
| 337 | + in VARCHAR/SUPER columns. Columns are derived from the first row, so all |
| 338 | + rows are expected to share the same keys. |
| 339 | +
|
| 340 | + Args: |
| 341 | + table_name: Fully qualified target table name (e.g. 'db.schema.table') |
| 342 | + data: List of dictionaries, each representing a row |
| 343 | +
|
| 344 | + Returns: |
| 345 | + Number of rows inserted |
| 346 | + """ |
| 347 | + if not data: |
| 348 | + return 0 |
| 349 | + |
| 350 | + columns = list(data[0].keys()) |
| 351 | + serialized = [ |
| 352 | + { |
| 353 | + col: json.dumps(row.get(col)) |
| 354 | + if isinstance(row.get(col), (dict, list)) |
| 355 | + else row.get(col) |
| 356 | + for col in columns |
| 357 | + } |
| 358 | + for row in data |
| 359 | + ] |
| 360 | + |
| 361 | + column_list = ', '.join(f'"{col}"' for col in columns) |
| 362 | + placeholders = ', '.join(f':{col}' for col in columns) |
| 363 | + command = f'INSERT INTO {table_name} ({column_list}) VALUES ({placeholders})' |
| 364 | + |
| 365 | + with self.get_connection() as connection: |
| 366 | + cursor = connection.cursor() |
| 367 | + try: |
| 368 | + cursor.executemany(command, serialized) |
| 369 | + connection.commit() |
| 370 | + return cursor.rowcount |
| 371 | + except RedshiftError as e: |
| 372 | + connection.rollback() |
| 373 | + logger.error(f'Insert error: {e}') |
| 374 | + raise |
| 375 | + finally: |
| 376 | + cursor.close() |
| 377 | + |
331 | 378 | def execute_transaction( |
332 | 379 | self, commands: List[Tuple[str, Optional[Dict[str, Any]]]] |
333 | 380 | ) -> bool: |
|
0 commit comments