-
Notifications
You must be signed in to change notification settings - Fork 31
Add support for RETURNING in SQLAlchemy dialect #363
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
Conversation
ca19003
to
aa8d274
Compare
@@ -165,6 +165,7 @@ class CrateDialect(default.DefaultDialect): | |||
type_compiler = CrateTypeCompiler | |||
supports_native_boolean = True | |||
colspecs = colspecs | |||
implicit_returning = True |
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.
Will this still work with older CrateDB versions which don't have RETURNING
?
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.
Yes, as long as you don't add a column with server_default=FetchedValue()
which requires RETURNING`, e.g:
class LogOld(Base):
__tablename__ = "logs_old"
__table_args__ = {"schema": "doc"}
ts = Column(DateTime, primary_key=True)
level = Column(String, primary_key=True)
message = Column(String, primary_key=True)
With the schema:
create table logs_old (ts timestamp with time zone, level text, message text)
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.
If implicit_returning
is False
, it would never add the RETURNING clause to the INSERT statement.
I guess what you mean is that we should not change behaviour for old versions. ( it will be a different exception).
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.
Just wanted to make sure that it doesn't add a RETURNING
to other statements that previously worked
Could you add a changes entry?
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.
Just wanted to make sure that it doesn't add a
RETURNING
to other statements that previously worked
I will test a bit more.
Could you add a changes entry?
Sure
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.
I found an issue when running one of our test suites, where an INSERT statement would add a RETURNING clause. However cannot reproduce it when the model is used outside of the test suite.
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.
Ok, so as soon as one column of the PK has a server side generated value, the SQLAlchemy ORM will append a RETURNING (in order to get the full PK for the model instance).
Example that works at the moment, but would fail with this change:
from sqlalchemy import create_engine, Column, String, DateTime, text
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
engine = create_engine(
"crate://",
connect_args={
"username": "crate",
"servers": "localhost:4200",
},
)
Session = sessionmaker(bind=engine)
Base = declarative_base(bind=Session)
class Event(Base):
__tablename__ = "event"
__table_args__ = {"schema": "doc"}
ts = Column("ts", DateTime, primary_key=True, server_default=text("current_timestamp"))
event = Column("event", String, primary_key=True)
if __name__ == "__main__":
session = Session()
o = Event(event="status")
session.add(o)
session.commit()
print(o)
CREATE TABLE doc.event (
ts TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
event TEXT
)
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.
I am not sure if this is a show stopper, because having the primary key in the model but not in the database is an awful workaround for not being able to use the FetchedValue() for _id. What do you think?
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 users override the implicit_returning
value? If so, I think a (breaking?) changes entry that explains the impact of the change and how to work around it if necessary should be good enough.
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.
Yes, you can override it when creating the engine: create_engine('crate://',..., implicit_returning=False)
.
Not sure why Python 3.5 keeps failing with |
This will enable the usage of `FetchedValue()` as server side default for primary keys in the declarative model. ```python import random from sqlalchemy import create_engine, inspect, func, Column, String, DateTime from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker from sqlalchemy.schema import FetchedValue engine = create_engine( "crate://", connect_args={ "username": "crate", }, ) Session = sessionmaker(bind=engine) Base = declarative_base(bind=engine) class Log(Base): __tablename__ = "logs" __table_args__ = {"schema": "doc"} __mapper_args__ = {"exclude_properties": ["id"]} id = Column("_id", String, server_default=FetchedValue(), primary_key=True) ts = Column(DateTime, server_default=func.current_timestamp()) level = Column(String) message = Column(String) if __name__ == "__main__": o = Log(level="info", message="Hello World") session = Session() session.add(o) session.commit() print(f"{o.id=}, {o.ts=}, {o.level=}, {o.message=}") ```
aa8d274
to
e0d18f1
Compare
Summary of the changes / Why this is an improvement
Example: