Move user profile image url into the users.details field (#5697)

Makes the details field a JSONB field per pg doc recommendations.

Update model.all() method to work properly now that profile_image_url
is not an independent field.

Closes #4469
This commit is contained in:
Jesse 2022-02-02 14:03:02 -06:00 committed by GitHub
parent 4164a42aab
commit 49fe29579a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 65 additions and 3 deletions

View File

@ -0,0 +1,60 @@
"""Convert user details to jsonb and move user profile image url into details column
Revision ID: fd4fc850d7ea
Revises: 89bc7873a3e0
Create Date: 2022-01-31 15:24:16.507888
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
from redash.models import db
# revision identifiers, used by Alembic.
revision = 'fd4fc850d7ea'
down_revision = '89bc7873a3e0'
branch_labels = None
depends_on = None
def upgrade():
connection = op.get_bind()
### commands auto generated by Alembic - please adjust! ###
op.alter_column('users', 'details',
existing_type=postgresql.JSON(astext_type=sa.Text()),
type_=postgresql.JSONB(astext_type=sa.Text()),
existing_nullable=True,
existing_server_default=sa.text("'{}'::jsonb"))
### end Alembic commands ###
update_query = """
update users
set details = details::jsonb || ('{"profile_image_url": "' || profile_image_url || '"}')::jsonb
where 1=1
"""
connection.execute(update_query)
op.drop_column("users", "profile_image_url")
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
connection = op.get_bind()
op.add_column("users", sa.Column("profile_image_url", db.String(320), nullable=True))
update_query = """
update users set
profile_image_url = details->>'profile_image_url',
details = details - 'profile_image_url' ;
"""
connection.execute(update_query)
db.session.commit()
op.alter_column('users', 'details',
existing_type=postgresql.JSONB(astext_type=sa.Text()),
type_=postgresql.JSON(astext_type=sa.Text()),
existing_nullable=True,
existing_server_default=sa.text("'{}'::json"))
# ### end Alembic commands ###

View File

@ -1118,7 +1118,7 @@ class Dashboard(ChangeTrackingMixin, TimestampMixin, BelongsToOrgMixin, db.Model
query = (
Dashboard.query.options(
joinedload(Dashboard.user).load_only(
"id", "name", "_profile_image_url", "email"
"id", "name", "details", "email"
)
).distinct(Dashboard.created_at, Dashboard.slug)
.outerjoin(Widget)

View File

@ -85,7 +85,6 @@ class User(
org = db.relationship("Organization", backref=db.backref("users", lazy="dynamic"))
name = Column(db.String(320))
email = Column(EmailType)
_profile_image_url = Column("profile_image_url", db.String(320), nullable=True)
password_hash = Column(db.String(128), nullable=True)
group_ids = Column(
"groups", MutableList.as_mutable(postgresql.ARRAY(key_type("Group"))), nullable=True
@ -94,7 +93,7 @@ class User(
disabled_at = Column(db.DateTime(True), default=None, nullable=True)
details = Column(
MutableDict.as_mutable(postgresql.JSON),
MutableDict.as_mutable(postgresql.JSONB),
nullable=True,
server_default="{}",
default={},
@ -102,6 +101,9 @@ class User(
active_at = json_cast_property(
db.DateTime(True), "details", "active_at", default=None
)
_profile_image_url = json_cast_property(
db.Text(), "details", "profile_image_url", default=None
)
is_invitation_pending = json_cast_property(
db.Boolean(True), "details", "is_invitation_pending", default=False
)