Add createdBy field on custom object creation (#6529)

In this PR, I'm:
- adding createdBy field (type ACTOR) on custom objects when created
- moving `name` and `position` default column to the set of columns
automatically creation on object creation
- fixing a bug on mutations (update / create), if the targetted object
has a 'data' custom field, it was conflicting with the payload ==> I
feel we need to refactor this part of the code but we can keep this for
a bit later as we plan to move out of pg_graphql

<img width="1198" alt="image"
src="https://github.com/user-attachments/assets/891c4a97-bab1-415c-8551-dabd5996a794">
This commit is contained in:
Charles Bochet
2024-08-04 13:12:24 +02:00
committed by GitHub
parent e2b42ee6c9
commit e787215e15
9 changed files with 66 additions and 46 deletions

View File

@ -90,6 +90,7 @@ export const generateEmptyFieldValue = (
case FieldMetadataType.Actor: { case FieldMetadataType.Actor: {
return { return {
source: 'MANUAL', source: 'MANUAL',
workspaceMemberId: null,
name: '', name: '',
}; };
} }

View File

@ -2,15 +2,15 @@ import { Injectable, Logger } from '@nestjs/common';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import { WorkspaceQueryBuilderOptions } from 'src/engine/api/graphql/workspace-query-builder/interfaces/workspace-query-builder-options.interface';
import { Record as IRecord } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface'; import { Record as IRecord } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface';
import { WorkspaceQueryBuilderOptions } from 'src/engine/api/graphql/workspace-query-builder/interfaces/workspace-query-builder-options.interface';
import { CreateManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; import { CreateManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { stringifyWithoutKeyQuote } from 'src/engine/api/graphql/workspace-query-builder/utils/stringify-without-key-quote.util'; import { stringifyWithoutKeyQuote } from 'src/engine/api/graphql/workspace-query-builder/utils/stringify-without-key-quote.util';
import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util'; import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util';
import { FieldsStringFactory } from './fields-string.factory';
import { ArgsAliasFactory } from './args-alias.factory'; import { ArgsAliasFactory } from './args-alias.factory';
import { FieldsStringFactory } from './fields-string.factory';
@Injectable() @Injectable()
export class CreateManyQueryFactory { export class CreateManyQueryFactory {
@ -30,8 +30,9 @@ export class CreateManyQueryFactory {
options.fieldMetadataCollection, options.fieldMetadataCollection,
options.objectMetadataCollection, options.objectMetadataCollection,
); );
const computedArgs = this.argsAliasFactory.create(
args, const computedArgsData = this.argsAliasFactory.create(
args.data,
options.fieldMetadataCollection, options.fieldMetadataCollection,
); );
@ -40,7 +41,7 @@ export class CreateManyQueryFactory {
insertInto${computeObjectTargetTable( insertInto${computeObjectTargetTable(
options.objectMetadataItem, options.objectMetadataItem,
)}Collection(objects: ${stringifyWithoutKeyQuote( )}Collection(objects: ${stringifyWithoutKeyQuote(
computedArgs.data.map((datum) => ({ computedArgsData.map((datum) => ({
id: uuidv4(), id: uuidv4(),
...datum, ...datum,
})), })),

View File

@ -1,10 +1,10 @@
import { Injectable, Logger } from '@nestjs/common'; import { Injectable, Logger } from '@nestjs/common';
import { WorkspaceQueryBuilderOptions } from 'src/engine/api/graphql/workspace-query-builder/interfaces/workspace-query-builder-options.interface';
import { import {
RecordFilter, RecordFilter,
RecordOrderBy, RecordOrderBy,
} from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface'; } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface';
import { WorkspaceQueryBuilderOptions } from 'src/engine/api/graphql/workspace-query-builder/interfaces/workspace-query-builder-options.interface';
import { FindManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; import { FindManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util'; import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util';

View File

@ -7,9 +7,9 @@ import {
import { WorkspaceQueryBuilderOptions } from 'src/engine/api/graphql/workspace-query-builder/interfaces/workspace-query-builder-options.interface'; import { WorkspaceQueryBuilderOptions } from 'src/engine/api/graphql/workspace-query-builder/interfaces/workspace-query-builder-options.interface';
import { UpdateManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; import { UpdateManyResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { stringifyWithoutKeyQuote } from 'src/engine/api/graphql/workspace-query-builder/utils/stringify-without-key-quote.util';
import { FieldsStringFactory } from 'src/engine/api/graphql/workspace-query-builder/factories/fields-string.factory';
import { ArgsAliasFactory } from 'src/engine/api/graphql/workspace-query-builder/factories/args-alias.factory'; import { ArgsAliasFactory } from 'src/engine/api/graphql/workspace-query-builder/factories/args-alias.factory';
import { FieldsStringFactory } from 'src/engine/api/graphql/workspace-query-builder/factories/fields-string.factory';
import { stringifyWithoutKeyQuote } from 'src/engine/api/graphql/workspace-query-builder/utils/stringify-without-key-quote.util';
import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util'; import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util';
export interface UpdateManyQueryFactoryOptions export interface UpdateManyQueryFactoryOptions
@ -37,13 +37,13 @@ export class UpdateManyQueryFactory {
options.objectMetadataCollection, options.objectMetadataCollection,
); );
const computedArgs = this.argsAliasFactory.create( const computedArgsData = this.argsAliasFactory.create(
args, args.data,
options.fieldMetadataCollection, options.fieldMetadataCollection,
); );
const argsData = { const argsData = {
...computedArgs.data, ...computedArgsData,
updatedAt: new Date().toISOString(), updatedAt: new Date().toISOString(),
}; };

View File

@ -1,14 +1,14 @@
import { Injectable, Logger } from '@nestjs/common'; import { Injectable, Logger } from '@nestjs/common';
import { WorkspaceQueryBuilderOptions } from 'src/engine/api/graphql/workspace-query-builder/interfaces/workspace-query-builder-options.interface';
import { Record as IRecord } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface'; import { Record as IRecord } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface';
import { WorkspaceQueryBuilderOptions } from 'src/engine/api/graphql/workspace-query-builder/interfaces/workspace-query-builder-options.interface';
import { UpdateOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; import { UpdateOneResolverArgs } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface';
import { stringifyWithoutKeyQuote } from 'src/engine/api/graphql/workspace-query-builder/utils/stringify-without-key-quote.util'; import { stringifyWithoutKeyQuote } from 'src/engine/api/graphql/workspace-query-builder/utils/stringify-without-key-quote.util';
import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util'; import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util';
import { FieldsStringFactory } from './fields-string.factory';
import { ArgsAliasFactory } from './args-alias.factory'; import { ArgsAliasFactory } from './args-alias.factory';
import { FieldsStringFactory } from './fields-string.factory';
@Injectable() @Injectable()
export class UpdateOneQueryFactory { export class UpdateOneQueryFactory {
@ -28,13 +28,14 @@ export class UpdateOneQueryFactory {
options.fieldMetadataCollection, options.fieldMetadataCollection,
options.objectMetadataCollection, options.objectMetadataCollection,
); );
const computedArgs = this.argsAliasFactory.create(
args, const computedArgsData = this.argsAliasFactory.create(
args.data,
options.fieldMetadataCollection, options.fieldMetadataCollection,
); );
const argsData = { const argsData = {
...computedArgs.data, ...computedArgsData,
id: undefined, // do not allow updating an existing object's id id: undefined, // do not allow updating an existing object's id
updatedAt: new Date().toISOString(), updatedAt: new Date().toISOString(),
}; };
@ -45,7 +46,7 @@ export class UpdateOneQueryFactory {
options.objectMetadataItem, options.objectMetadataItem,
)}Collection(set: ${stringifyWithoutKeyQuote( )}Collection(set: ${stringifyWithoutKeyQuote(
argsData, argsData,
)}, filter: { id: { eq: "${computedArgs.id}" } }) { )}, filter: { id: { eq: "${args.id}" } }) {
affectedCount affectedCount
records { records {
${fieldsString} ${fieldsString}

View File

@ -265,6 +265,20 @@ export class ObjectMetadataService extends TypeOrmQueryService<ObjectMetadataEnt
workspaceId: objectMetadataInput.workspaceId, workspaceId: objectMetadataInput.workspaceId,
defaultValue: 'now', defaultValue: 'now',
}, },
{
standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.createdBy,
type: FieldMetadataType.ACTOR,
name: 'createdBy',
label: 'Created By',
icon: 'IconCreativeCommonsSa',
description: 'The creator of the record',
isNullable: false,
isActive: true,
isCustom: false,
isSystem: false,
workspaceId: objectMetadataInput.workspaceId,
defaultValue: { name: "''", source: "'MANUAL'" },
},
{ {
standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.position, standardId: CUSTOM_OBJECT_STANDARD_FIELD_IDS.position,
type: FieldMetadataType.POSITION, type: FieldMetadataType.POSITION,

View File

@ -208,31 +208,4 @@ export const buildMigrationsForCustomObjectRelations = (
}, },
], ],
}, },
{
name: computeObjectTargetTable(createdObjectMetadata),
action: WorkspaceMigrationTableActionType.ALTER,
columns: [
{
action: WorkspaceMigrationColumnActionType.CREATE,
columnName: 'position',
columnType: 'float',
isNullable: true,
defaultValue: null,
} satisfies WorkspaceMigrationColumnCreate,
],
} satisfies WorkspaceMigrationTableAction,
// This is temporary until we implement mainIdentifier
{
name: computeObjectTargetTable(createdObjectMetadata),
action: WorkspaceMigrationTableActionType.ALTER,
columns: [
{
action: WorkspaceMigrationColumnActionType.CREATE,
columnName: 'name',
columnType: 'text',
defaultValue: "'Untitled'",
isNullable: false,
} satisfies WorkspaceMigrationColumnCreate,
],
} satisfies WorkspaceMigrationTableAction,
]; ];

View File

@ -1,6 +1,10 @@
import { TableColumnOptions } from 'typeorm'; import { TableColumnOptions } from 'typeorm';
export const customTableDefaultColumns: TableColumnOptions[] = [ import { FieldActorSource } from 'src/engine/metadata-modules/field-metadata/composite-types/actor.composite-type';
export const customTableDefaultColumns = (
tableName: string,
): TableColumnOptions[] => [
{ {
name: 'id', name: 'id',
type: 'uuid', type: 'uuid',
@ -22,4 +26,30 @@ export const customTableDefaultColumns: TableColumnOptions[] = [
type: 'timestamptz', type: 'timestamptz',
isNullable: true, isNullable: true,
}, },
{
name: 'position',
type: 'float',
isNullable: true,
},
{
name: 'name',
type: 'text',
isNullable: false,
default: "'Untitled'",
},
{
name: 'createdBySource',
type: 'enum',
enumName: `${tableName}_createdBySource_enum`,
enum: Object.values(FieldActorSource),
isNullable: false,
default: `'${FieldActorSource.MANUAL}'`,
},
{ name: 'createdByWorkspaceMemberId', type: 'uuid', isNullable: true },
{
name: 'createdByName',
type: 'text',
isNullable: false,
default: "''",
},
]; ];

View File

@ -227,7 +227,7 @@ export class WorkspaceMigrationRunnerService {
new Table({ new Table({
name: tableName, name: tableName,
schema: schemaName, schema: schemaName,
columns: customTableDefaultColumns, columns: customTableDefaultColumns(tableName),
}), }),
true, true,
); );