-
Notifications
You must be signed in to change notification settings - Fork 262
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement column defaults for INSERT/UPDATE #206
base: master
Are you sure you want to change the base?
Conversation
MySQL rounds datetimes to seconds.
9d9080a
to
f66013e
Compare
Co-authored-by: Rafał Pitoń <[email protected]>
Any updates on this? |
It's difficult because I'm not really sure if we want this functionality or not. |
@tomchristie I am just curious. Why would you not want this functionality? I am currently writing a application with fastapi and encode/databases and i want the timestamp to be created on insert. currently i don't have a way of doing this. |
It also seems necessary for UUID primary keys, which are pretty common these days. |
The column defaults are higher level sqla API ("Query") than the API used in The problem can be solved outside of |
@vmarkovtsev SQLAlchemy core does have defaults, see the |
+1 for this. I followed the FastAPI tutorial and tried to implement a UUID for sqlite. I couldn't figure out why it didn't work until I specifically checked this repo for issues around the defaults. |
This is a must, thanks |
Approve this pls |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry fellows, I wish I approved this, but this looks too hacky right now to be included as a general solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are my suggestions 👍
|
||
# 2 paths where we apply column defaults: | ||
# - values are supplied (the object must be a ValuesBase) | ||
# - values is None but the object is a ValuesBase | ||
if values is not None and not isinstance(query, ValuesBase): | ||
raise TypeError("values supplied but query doesn't support .values()") | ||
|
||
if values is not None or isinstance(query, ValuesBase): | ||
values = Connection._apply_column_defaults(query, values) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# 2 paths where we apply column defaults: | |
# - values are supplied (the object must be a ValuesBase) | |
# - values is None but the object is a ValuesBase | |
if values is not None and not isinstance(query, ValuesBase): | |
raise TypeError("values supplied but query doesn't support .values()") | |
if values is not None or isinstance(query, ValuesBase): | |
values = Connection._apply_column_defaults(query, values) | |
elif values: | |
assert isinstance(query, ValuesBase) | |
values = self._apply_column_defaults(query, values) |
if default.is_sequence: # pragma: no cover | ||
# TODO: support sequences | ||
continue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assert not default.is_sequence, "sequences are not supported, PRs welcome"
values = values or {} | ||
|
||
for column in query.table.c: | ||
if column.name in values: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
values
can have columns as keys, in such cases this will be always false
continue | ||
elif default.is_callable: | ||
value = default.arg(FakeExecutionContext()) | ||
elif default.is_clause_element: # pragma: no cover |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
elif default.is_clause_element: # pragma: no cover | |
assert not default.is_clause_element, "clause defaults are not supported, PRs welcome" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- can you please group assertions together
continue | ||
else: | ||
value = default.arg | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
blows up loudly and clearly. | ||
""" | ||
|
||
def __getattr__(self, _: str) -> typing.NoReturn: # pragma: no cover |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should cover this by another test which tests raising NotImplementedError
@@ -489,3 +531,20 @@ def __repr__(self) -> str: | |||
|
|||
def __eq__(self, other: typing.Any) -> bool: | |||
return str(self) == str(other) | |||
|
|||
|
|||
class FakeExecutionContext: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
class FakeExecutionContext: | |
class DummyExecutionContext: |
(it's not completely fake, after all)
""" | ||
|
||
def __getattr__(self, _: str) -> typing.NoReturn: # pragma: no cover | ||
raise NotImplementedError( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
btw: my own custom implementation of this (yep, I have a similar hack in my prod), I pass the current values
to this context so that it becomes much more useful.
Any updates on this? |
This PR implements usage of column defaults from SQLAlchemy. In regular SQLAlchemy the default column values are fetched using
ExecutionContext._exec_default
. However, we don't use theExecutionContext
here, so a function is implemented to take its place for column defaults.Fixes #72