feat: Adding support for new FieldMetadataType with Postgres enums#2674
feat: Adding support for new FieldMetadataType with Postgres enums#2674
Conversation
| { | ||
| id: 'currencyCode', | ||
| type: FieldMetadataType.TEXT, | ||
| type: FieldMetadataType.VARCHAR, |
There was a problem hiding this comment.
Temporary workaround as composite type doesn't use the correct type in database, TEXT should be text not varchar.
cc @Weiko
There was a problem hiding this comment.
Ok, we will need to migrate our DB though (to change the metadata). cc @charlesBochet
There was a problem hiding this comment.
If it's a temporary workaround, maybe we should actually use TEXT and run the migration to have the final result directly? (which is having text in the workspace schema I guess?). Except if we want to handle SHORT_TEXT type or something and use varchar
There was a problem hiding this comment.
Tbh, I'm pretty sure varchar is the same as text for postgres if you don't define a particular size
There was a problem hiding this comment.
Yes see here
The TEXT data type can store a string with unlimited length.
If you do not specify the n integer for the VARCHAR data type, it behaves like the TEXT datatype. The performance of the VARCHAR (without the size n) and TEXT are the same.
https://www.postgresqltutorial.com/postgresql-tutorial/postgresql-char-varchar-text/
There was a problem hiding this comment.
Do we want to store currency in an enum in the future?
Plus: data is more robust
Minus: migration when geopolitics evolves :D
There was a problem hiding this comment.
Regarding varchar vs text, I don't think we should use both. I think varchar should be good, and agree we should avoid generating migrations if possible
There was a problem hiding this comment.
So not sure to understand the motivation behind this change
There was a problem hiding this comment.
@Weiko: Ok good point that Postgres handle varchar without length in the same way as text.
I'm ok with avoiding migrations, but I don't really like to have inconsistence between the metadata and what is actually stored in the database.
For better explanation @charlesBochet, instead of always redefining the composite types like Link or Currency, I've moved the composite types definitions that initially was in the schema-builder into the field-metadata.
That way we're using the same object to define them. But it involve creating the FieldMetadata for the inner fields of composite types, and that was manually done before by manually putting the type varchar.
But actually varchar is not mapped in our FieldMetadataType.
The first thing I does is putting the type FieldMetadataType.TEXT for this fields, but this one is converted to a text column type in Postgres not a varchar.
It's why I've created a temporary type to avoid breaking changes, but from what @Weiko says, I can still put TEXT, we'll just have some inconsistency but it should work the same.
There was a problem hiding this comment.
Do we want to store currency in an enum in the future? Plus: data is more robust Minus: migration when geopolitics evolves :D
It's something that we can consider
server/src/metadata/workspace-migration/factories/abstract.factory.ts
Outdated
Show resolved
Hide resolved
server/src/metadata/workspace-migration/factories/enum-column-action.factory.ts
Show resolved
Hide resolved
server/src/workspace/workspace-migration-runner/services/workspace-migration-enum.service.ts
Show resolved
Hide resolved
| ) { | ||
| const enumValues = migrationColumn.enum; | ||
|
|
||
| // TODO: Maybe we can do something better if we can recreate the old `TableColumn` object |
There was a problem hiding this comment.
Try to rely on TypeORM by recreating the old TableColumn.
This is needed to support updating other properties at the same time.
In this PR we can't change the options of a FieldMetadata with the defaultValue at the same time.
There was a problem hiding this comment.
Could you elaborate more here? What happens if we do both at same time?
There was a problem hiding this comment.
If we currently do both at the same time, TypeORM migrations will brakes enum migrations an drop the enum column before recreating it, so all the data will be lost
server/src/database/typeorm/metadata/migrations/1700663879152-addEnumOptions.ts
Show resolved
Hide resolved
| { | ||
| id: 'currencyCode', | ||
| type: FieldMetadataType.TEXT, | ||
| type: FieldMetadataType.VARCHAR, |
There was a problem hiding this comment.
Ok, we will need to migrate our DB though (to change the metadata). cc @charlesBochet
| { | ||
| id: 'currencyCode', | ||
| type: FieldMetadataType.TEXT, | ||
| type: FieldMetadataType.VARCHAR, |
There was a problem hiding this comment.
If it's a temporary workaround, maybe we should actually use TEXT and run the migration to have the final result directly? (which is having text in the workspace schema I guess?). Except if we want to handle SHORT_TEXT type or something and use varchar
| { | ||
| id: 'currencyCode', | ||
| type: FieldMetadataType.TEXT, | ||
| type: FieldMetadataType.VARCHAR, |
There was a problem hiding this comment.
Tbh, I'm pretty sure varchar is the same as text for postgres if you don't define a particular size
| { | ||
| id: 'currencyCode', | ||
| type: FieldMetadataType.TEXT, | ||
| type: FieldMetadataType.VARCHAR, |
There was a problem hiding this comment.
Yes see here
The TEXT data type can store a string with unlimited length.
If you do not specify the n integer for the VARCHAR data type, it behaves like the TEXT datatype. The performance of the VARCHAR (without the size n) and TEXT are the same.
https://www.postgresqltutorial.com/postgresql-tutorial/postgresql-char-varchar-text/
| { | ||
| id: 'currencyCode', | ||
| type: FieldMetadataType.TEXT, | ||
| type: FieldMetadataType.VARCHAR, |
There was a problem hiding this comment.
So instead maybe we can keep varchar, that would avoid unnecessary migrations @magrinj @charlesBochet
Ideally we should keep things consistent but looks like in this case it's fine
| } from 'src/metadata/workspace-migration/workspace-migration.entity'; | ||
| import { FieldMetadataType } from 'src/metadata/field-metadata/field-metadata.entity'; | ||
|
|
||
| export class AbstractFactory<T extends FieldMetadataType | 'default'> |
There was a problem hiding this comment.
Can we use a less generic name instead of AbstractFactory? WorkspaceMigrationFactory or something like that?
There was a problem hiding this comment.
@Weiko Yes we can, but actually AbstractFactory should only be used inside this folder.
I'll rename it WorkspaceColumnActionAbstractFactory
| import { WorkspaceMigrationColumnAlter } from 'src/metadata/workspace-migration/workspace-migration.entity'; | ||
|
|
||
| @Injectable() | ||
| export class WorkspaceMigrationEnumService { |
There was a problem hiding this comment.
Should we prefix custom enums with "_"? @charlesBochet
There was a problem hiding this comment.
I think it will because the name is based on: ${tableName}_${migrationColumn.columnName}
There was a problem hiding this comment.
You mean because of table name? What if we add a custom enum on a standard object? As for the column name then yes we just to make sure we put an _ there when creating the migration
There was a problem hiding this comment.
@Weiko Actually enum names are based on the field name, so if the field is _myField the enum will be something like _myTable__myField_enum
|
|
||
| ARG PG_MAIN_VERSION | ||
| ARG PG_GRAPHQL_VERSION=1.3.0 | ||
| ARG PG_GRAPHQL_VERSION=1.4.2 |
There was a problem hiding this comment.
I will also need to update our local install script
server/src/database/typeorm/metadata/migrations/1700663879152-addEnumOptions.ts
Show resolved
Hide resolved
| { | ||
| id: 'currencyCode', | ||
| type: FieldMetadataType.TEXT, | ||
| type: FieldMetadataType.VARCHAR, |
There was a problem hiding this comment.
Do we want to store currency in an enum in the future?
Plus: data is more robust
Minus: migration when geopolitics evolves :D
| { | ||
| id: 'currencyCode', | ||
| type: FieldMetadataType.TEXT, | ||
| type: FieldMetadataType.VARCHAR, |
There was a problem hiding this comment.
Regarding varchar vs text, I don't think we should use both. I think varchar should be good, and agree we should avoid generating migrations if possible
| { | ||
| id: 'currencyCode', | ||
| type: FieldMetadataType.TEXT, | ||
| type: FieldMetadataType.VARCHAR, |
There was a problem hiding this comment.
So not sure to understand the motivation behind this change
| const updatedFieldMetadata = await super.updateOne(id, record); | ||
|
|
||
| if (record.options || record.defaultValue) { | ||
| await this.workspaceMigrationService.createCustomMigration( |
There was a problem hiding this comment.
I am not sure about the createCustomMigration API long term. I feel that we should maybe provide something more restrictive: createColumn, udpateColumnType, updateEnumOptions...
There was a problem hiding this comment.
We can let it like this for now
| import { WorkspaceMigrationColumnAlter } from 'src/metadata/workspace-migration/workspace-migration.entity'; | ||
|
|
||
| @Injectable() | ||
| export class WorkspaceMigrationEnumService { |
There was a problem hiding this comment.
I think it will because the name is based on: ${tableName}_${migrationColumn.columnName}
| ); | ||
|
|
||
| // Update existing rows to handle missing values | ||
| await this.handleMissingEnumValues( |
There was a problem hiding this comment.
this is the first migration that will touch the data. I am very curious to see how it behaves on production.
On a regular project I would avoid that, but as we are doing migration per workspace, it's actually great. It will help migrating between versions of twenty handling data migration too and we will be able to test it on test workspaces, tier 3 workspaces before trying it on more important workspaces or clients!
| ); | ||
| } | ||
|
|
||
| private async renameEnumType( |
There was a problem hiding this comment.
so much complexity, but all steps make sense to me
| ) { | ||
| const enumValues = migrationColumn.enum; | ||
|
|
||
| // TODO: Maybe we can do something better if we can recreate the old `TableColumn` object |
There was a problem hiding this comment.
Could you elaborate more here? What happens if we do both at same time?
feat: wip enum type feat: try to alter enum feat: wip enum feat: wip enum feat: schema-builder can handle enum fix: return default value in field metadata response
This reverts commit 3857539.
Description
This PR introduces support for a new
FieldMetadataType, utilizing Postgres enums to enhance our data modeling capabilities. We have introduced three new types:RATING,SELECT, andMULTI_SELECT.Key features
Creation and Update of FieldMetadata:
FieldMetadatawith additional options for these enum types. For instance, when creating a field with the typeMULTI_SELECT, the options include properties likeposition,color,label, andvalue.FieldMetadata:Options update
idfor each option within aFieldMetadatatype. Thisidis crucial for theupdateOneFieldmutation, ensuring a seamless transition between old and new enum values.Utilization in Document queries:
Frontend Integration:
FieldMetadataoptions with the enum values. This mapping will deduce properties such ascolorandposition, facilitating the way enums are updated in all the views.Known issues
Filtering on multiple choices enum doesn't work, it's due to
pg_graphqlthat is not handling them properly supabase/pg_graphql#458