DEV Community

박준희
박준희

Posted on • Originally published at aicoreutility.com

Node.js Build Log JSONB Parsing Error and asyncpg Type Mismatch Issues

Node.js Build Log JSONB Parsing Error and asyncpg Type Mismatch

I ran into quite a bit of trouble processing build log data, specifically with JSONB field parsing errors and data type mismatches occurring in the asynchronous PostgreSQL library (asyncpg). I'm writing this post to help anyone else facing similar issues.

Attempts and Pitfalls

Initially, I added defensive coding to the parsing logic to handle cases where the summary field in JSONB data might come in an unexpected string format. But the problem didn't end there. I discovered that the asyncpg library couldn't directly accept a date object and only accepted strings.

# Example: Initial parsing attempt (defending against string returns)
try:
    summary_data = json.loads(row.summary)
except json.JSONDecodeError:
    summary_data = {} # Or handle with a default

# Example: Suspected asyncpg type mismatch point
# row.date was a datetime object, but asyncpg seemed to expect a string.
await db.execute("INSERT INTO build_logs (date, summary) VALUES ($1, $2)", row.date, row.summary)
Enter fullscreen mode Exit fullscreen mode

After confirming that asyncpg was failing because it couldn't convert the date object to a string, I modified the code to directly pass the date object to the date column in the build_log table.

# Attempt to resolve asyncpg type mismatch
# row.date is a datetime object
await db.execute("INSERT INTO build_logs (date, summary) VALUES ($1, $2)", row.date.isoformat(), row.summary)
Enter fullscreen mode Exit fullscreen mode

During this process, I also found a KeyError in the get_model_for_tier function where the task name for the 'lite' tier was being referenced incorrectly.

Cause

There were two main causes. First, the asyncpg library was causing unexpected type conversion errors when directly passing date objects to the database. Second, a KeyError existed in a specific logic section due to incorrect referencing of the task name for the 'lite' tier.

Solution

For the JSONB parsing errors, I handled it by explicitly parsing using json.loads. The asyncpg type mismatch issue was resolved by converting the date object to a string using .isoformat() before passing it. Additionally, I corrected the incorrect task reference for the 'lite' tier within the get_model_for_tier function.

# Final solution code (simplified)
import json
from datetime import datetime

# ... (db connection and other setups)

async def process_build_log(row):
    # Handling JSONB parsing errors
    try:
        summary_data = json.loads(row.summary)
    except json.JSONDecodeError:
        summary_data = {"error": "Invalid JSON"} # Or another default

    # Resolving asyncpg type mismatch (converting date object to isoformat string)
    date_str = row.date.isoformat() if isinstance(row.date, datetime) else str(row.date)

    await db.execute(
        "INSERT INTO build_logs (date, summary) VALUES ($1, $2)",
        date_str,
        json.dumps(summary_data) # Storing back as a JSON string
    )

def get_model_for_tier(tier):
    task_map = {
        'standard': 'standard_task',
        'lite': 'lite_task', # Corrected to the proper task name
        'premium': 'premium_task',
    }
    return task_map.get(tier)

# ... (subsequent logic)
Enter fullscreen mode Exit fullscreen mode

Results

  • The process of parsing and storing JSONB data for build logs has been stabilized.
  • Type mismatch errors during database write operations using the asyncpg library have been eliminated.
  • The KeyError that occurred when fetching the 'lite' tier has been resolved, and that functionality is now working correctly.

Takeaways — Avoiding the Same Pitfalls

  • [ ] Be aware that unexpected type conversion errors can occur when using database libraries.
  • [ ] Explicitly convert objects like date and datetime to the format required by the database library (usually strings). .isoformat() is useful here.
  • [ ] When handling JSON data, always remember to include exception handling for cases like json.JSONDecodeError.
  • [ ] In complex logic, keep the possibility of KeyError in mind when referencing dictionary keys and utilize methods like .get() or try-except blocks.

Top comments (0)