Skip to content

Conversation

alxtkr77
Copy link
Member

@alxtkr77 alxtkr77 commented Sep 9, 2025

No description provided.

@alxtkr77 alxtkr77 force-pushed the timescaledb_add_verification branch from 0b50684 to 32c858a Compare September 9, 2025 11:48
@alxtkr77 alxtkr77 changed the title Timescaledb: add column nullability check on insert Timescaledb: add column nullability check on insert and switch to psycopg3 Sep 9, 2025
@alxtkr77 alxtkr77 force-pushed the timescaledb_add_verification branch from 32c858a to d3d2e7a Compare September 9, 2025 14:29
Copy link
Collaborator

@gtopper gtopper left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great, but I did have a few comments :)

rows = await cur.fetchall()

if not rows:
raise ValueError(f"Table '{schema_name}.{self._table}' not found or has no columns")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be nice to tell the user which one it is.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will fix

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant telling the user that the table doesn't exist, or that it has no columns. Pretty sure we can tell from whether rows is None or an empty list. It's nice to avoid ambiguity in the error message.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

return

# Get table schema for validation on first use
schema = await self._get_table_schema()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we shouldn't just do it in _init(), so that there's no need to cache it, just initialize it on startup.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue is that the current architecture deliberately keeps _init() synchronous and defers async operations. If we wanted to do schema initialization in _init(), we'd need to use synchronous database operations.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, the init sequence is synchronous. It would be good to do it there, but it's not very important.

invalid_data = "this_is_not_a_dictionary"

# Should raise TypeError for non-dictionary data (the error occurs in the parent Writer class)
with pytest.raises(TypeError, match=r"string indices must be integers"):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're already testing it, maybe we should raise a better error?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will fix

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you might have missed this one though since this line wasn't updated.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually the error is raise by Writer::_event_to_writer_entry(), so not sure what to test there

@alxtkr77 alxtkr77 force-pushed the timescaledb_add_verification branch from ea770dd to 8356ba6 Compare September 15, 2025 15:22
Copy link
Collaborator

@gtopper gtopper left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good stuff. A couple more things to consider.

Comment on lines 157 to 158
except Exception as e:
print(f"Cleanup error: {e}")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just let it be raised normally.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

Comment on lines 366 to 368
# Cleanup
with connection.cursor() as cursor:
cursor.execute(f"DROP TABLE IF EXISTS {validation_table} CASCADE;")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cleanup block will not run in case of a test failure.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will fix

Comment on lines 451 to 454
# Cleanup
with connection.cursor() as cursor:
cursor.execute(f"DROP TABLE IF EXISTS {schema_table} CASCADE;")
cursor.execute(f"DROP SCHEMA IF EXISTS {schema_name} CASCADE;")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cleanup block will not run in case of a test failure.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will fix

Comment on lines 492 to 493
# Cleanup
await target._terminate()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cleanup block will not run in case of a test failure.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will fix

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will fix

"""
)
cursor.execute(f"SELECT create_hypertable('{validation_table}', 'time');")
cursor.close()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't run in case of error.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will fix

rows = await cur.fetchall()

if not rows:
raise ValueError(f"Table '{schema_name}.{self._table}' not found or has no columns")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant telling the user that the table doesn't exist, or that it has no columns. Pretty sure we can tell from whether rows is None or an empty list. It's nice to avoid ambiguity in the error message.

return

# Get table schema for validation on first use
schema = await self._get_table_schema()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, the init sequence is synchronous. It would be good to do it there, but it's not very important.

invalid_data = "this_is_not_a_dictionary"

# Should raise TypeError for non-dictionary data (the error occurs in the parent Writer class)
with pytest.raises(TypeError, match=r"string indices must be integers"):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you might have missed this one though since this line wasn't updated.

Comment on lines 465 to 475
target = TimescaleDBTarget(
dsn=dsn_url,
table=table_name,
time_col="time",
columns=columns_config,
time_format=time_format,
max_events=10,
)

# Initialize the target
await target._async_init()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here too, I think it would be better to test within a graph rather than by calling the target's private methods.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will fix

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants