-
Notifications
You must be signed in to change notification settings - Fork 458
feat: Switch to JSONField for SDK metrics labels
#5833
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
base: main
Are you sure you want to change the base?
Conversation
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎ 3 Skipped Deployments
|
Docker builds report
|
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #5833 +/- ##
=======================================
Coverage 97.82% 97.82%
=======================================
Files 1258 1259 +1
Lines 44745 44747 +2
=======================================
+ Hits 43771 43773 +2
Misses 974 974 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Confirming this fix allows CockroachDB to work without needing to update Psycopg to 3.1+. |
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.
The migrations look redundant except if I am missing something? Can we see to merge them together maybe ?
|
@Zaimwa9 Indeed these migrations look very similar, but their purpose is actually different:
So, to answer your question, no, we can't merge these migrations as they cater for different scenarios, and I argue they are not in fact redundant. |
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.
Alright thanks for the details, I felt that under the hood there was a migration purpose
| operations = [ | ||
| migrations.AlterField( | ||
| model_name="apiusagebucket", | ||
| name="labels", | ||
| field=models.JSONField(default=dict), | ||
| ), | ||
| migrations.AlterField( | ||
| model_name="apiusageraw", | ||
| name="labels", | ||
| field=models.JSONField(default=dict), | ||
| ), | ||
| migrations.AlterField( | ||
| model_name="featureevaluationbucket", | ||
| name="labels", | ||
| field=models.JSONField(default=dict), | ||
| ), | ||
| migrations.AlterField( | ||
| model_name="featureevaluationraw", | ||
| name="labels", | ||
| field=models.JSONField(default=dict), | ||
| ), |
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.
To my understanding, this will lead to multiple alter column ... type statements. Is casting hstore to json as simple as that in, at least, Postgres?
I'm also curious as to the impact of this to existing installs.
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.
Good catch, we actually need a USING clause. Added in 091006e.
|
I forgot to add as notes to my last review: not actually requesting any changes unless proven necessary by the comment I added. |
| migrations.RunSQL( | ||
| # Only alter the columns that are currently hstore. | ||
| # See 0006_add_labels to understand why we are doing this. | ||
| sql=""" | ||
| DO $$ | ||
| BEGIN | ||
| FOR relname IN | ||
| SELECT c.relname | ||
| FROM pg_class c | ||
| JOIN pg_attribute a ON a.attrelid = c.oid | ||
| JOIN pg_type t ON a.atttypid = t.oid | ||
| WHERE c.relname IN ( | ||
| 'app_analytics_apiusagebucket', | ||
| 'app_analytics_apiusageraw', | ||
| 'app_analytics_featureevaluationbucket', | ||
| 'app_analytics_featureevaluationraw' | ||
| ) | ||
| AND a.attname = 'labels' | ||
| AND t.typname = 'hstore' | ||
| LOOP | ||
| EXECUTE format( | ||
| 'ALTER TABLE %I | ||
| ALTER COLUMN labels TYPE jsonb USING hstore_to_json(labels), | ||
| ALTER COLUMN labels SET DEFAULT ''{}''::jsonb', | ||
| relname | ||
| ); | ||
| END LOOP; | ||
| END | ||
| $$; | ||
| """, | ||
| # We don't want hstore in the database at all, | ||
| # so don't do anything for reverse SQL. | ||
| reverse_sql="", | ||
| ), |
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.
The SQL code looks fine, though I think we should benefit from the ORM abstraction until we need to fall back to raw SQL.
Here's an untested brain dump.
Given:
def upgrade_field(model_name: str, field_name: str) -> Callable[[Apps, SchemaEditor], None]:
def upgrade(apps: Apps, schema_editor: SchemaEditor) -> None:
model = apps.get_model("app_analytics", model_name)
field = model._meta.get_field(field_name)
if isinstance(field, models.JSONField):
continue
schema_editor.execute(f"""
ALTER TABLE {model._meta.db_table}
ALTER COLUMN {field.column} TYPE jsonb USING hstore_to_json({field.column}),
ALTER COLUMN {field.column} SET DEFAULT '{{}}'::jsonb
""")
return upgradeSuggested replacement for the SQL script:
| migrations.RunSQL( | |
| # Only alter the columns that are currently hstore. | |
| # See 0006_add_labels to understand why we are doing this. | |
| sql=""" | |
| DO $$ | |
| BEGIN | |
| FOR relname IN | |
| SELECT c.relname | |
| FROM pg_class c | |
| JOIN pg_attribute a ON a.attrelid = c.oid | |
| JOIN pg_type t ON a.atttypid = t.oid | |
| WHERE c.relname IN ( | |
| 'app_analytics_apiusagebucket', | |
| 'app_analytics_apiusageraw', | |
| 'app_analytics_featureevaluationbucket', | |
| 'app_analytics_featureevaluationraw' | |
| ) | |
| AND a.attname = 'labels' | |
| AND t.typname = 'hstore' | |
| LOOP | |
| EXECUTE format( | |
| 'ALTER TABLE %I | |
| ALTER COLUMN labels TYPE jsonb USING hstore_to_json(labels), | |
| ALTER COLUMN labels SET DEFAULT ''{}''::jsonb', | |
| relname | |
| ); | |
| END LOOP; | |
| END | |
| $$; | |
| """, | |
| # We don't want hstore in the database at all, | |
| # so don't do anything for reverse SQL. | |
| reverse_sql="", | |
| ), | |
| migrations.RunPython( | |
| code=upgrade_field("apiusagebucket", "labels"), | |
| reverse_code=migrations.RunPython.noop, | |
| ), | |
| migrations.RunPython( | |
| code=upgrade_field("apiusageraw", "labels"), | |
| reverse_code=migrations.RunPython.noop, | |
| ), | |
| migrations.RunPython( | |
| code=upgrade_field("featureevaluationbucket", "labels"), | |
| reverse_code=migrations.RunPython.noop, | |
| ), | |
| migrations.RunPython( | |
| code=upgrade_field("featureevaluationraw", "labels"), | |
| reverse_code=migrations.RunPython.noop, | |
| ), |
Thanks for submitting a PR! Please check the boxes below:
docs/if required so people know about the feature!Changes
This migrates all the
labelsfields added in #5623 tojsonbas thehstoresupport turned out to be problematic:hstoreextension requires enabling additional parameter sets in some cloud environments (e.g. Azure).Note that due to problem 1, I've removed the
CREATE EXTENSIONoperation from the original migration.How did you test this code?
Migrations and tests run ok.
Will be smoke-tested against CockroachDB as well.