Centralize metadata relations constant + simplification (#16901)
# Introduction As we introduced a new grain on relation extraction thanks to low level `SyncableEntity` and `WorkspaceRelatedEntity` we're able to strictly typesafe extract metadata entity The new constant centralizes both many to one and one to many constants metadata entity constants in a more strictly typesafe way. Remains only the flatEntityForeignKey aggregator which has to be chosen manually across all available targeted flat entity ids properties
This commit is contained in:
-142
@@ -1,142 +0,0 @@
|
||||
import { type AllMetadataName } from 'twenty-shared/metadata';
|
||||
import { type ExtractPropertiesThatEndsWithId } from 'twenty-shared/types';
|
||||
|
||||
import { type MetadataEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-entity.type';
|
||||
import { type MetadataFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity.type';
|
||||
|
||||
type ExtractEntityRelations<TEntity extends MetadataEntity<AllMetadataName>> = {
|
||||
[K in ExtractPropertiesThatEndsWithId<TEntity, 'id' | 'workspaceId'>]: K;
|
||||
};
|
||||
|
||||
type MetadataRelatedMetadataNames<T extends AllMetadataName> =
|
||||
keyof ExtractEntityRelations<MetadataEntity<T>>;
|
||||
|
||||
type MetadataNameAndRelations = {
|
||||
[TSourceMetadataName in AllMetadataName]: MetadataRelatedMetadataNames<TSourceMetadataName> extends never
|
||||
? Record<string, never>
|
||||
: {
|
||||
[K in MetadataRelatedMetadataNames<TSourceMetadataName>]?: {
|
||||
[TTargetMetadataName in AllMetadataName]?: {
|
||||
metadataName: TTargetMetadataName;
|
||||
flatEntityForeignKeyAggregator: keyof MetadataFlatEntity<TTargetMetadataName>;
|
||||
};
|
||||
}[AllMetadataName];
|
||||
};
|
||||
};
|
||||
|
||||
export const ALL_METADATA_RELATED_METADATA_BY_FOREIGN_KEY = {
|
||||
fieldMetadata: {
|
||||
objectMetadataId: {
|
||||
metadataName: 'objectMetadata',
|
||||
flatEntityForeignKeyAggregator: 'fieldMetadataIds',
|
||||
},
|
||||
},
|
||||
objectMetadata: {},
|
||||
view: {
|
||||
kanbanAggregateOperationFieldMetadataId: {
|
||||
metadataName: 'fieldMetadata',
|
||||
flatEntityForeignKeyAggregator: 'kanbanAggregateOperationViewIds',
|
||||
},
|
||||
calendarFieldMetadataId: {
|
||||
metadataName: 'fieldMetadata',
|
||||
flatEntityForeignKeyAggregator: 'calendarViewIds',
|
||||
},
|
||||
mainGroupByFieldMetadataId: {
|
||||
metadataName: 'fieldMetadata',
|
||||
flatEntityForeignKeyAggregator: 'mainGroupByFieldMetadataViewIds',
|
||||
},
|
||||
objectMetadataId: {
|
||||
metadataName: 'objectMetadata',
|
||||
flatEntityForeignKeyAggregator: 'viewIds',
|
||||
},
|
||||
},
|
||||
viewField: {
|
||||
viewId: {
|
||||
metadataName: 'view',
|
||||
flatEntityForeignKeyAggregator: 'viewFieldIds',
|
||||
},
|
||||
fieldMetadataId: {
|
||||
metadataName: 'fieldMetadata',
|
||||
flatEntityForeignKeyAggregator: 'viewFieldIds',
|
||||
},
|
||||
},
|
||||
viewGroup: {
|
||||
viewId: {
|
||||
metadataName: 'view',
|
||||
flatEntityForeignKeyAggregator: 'viewGroupIds',
|
||||
},
|
||||
},
|
||||
index: {
|
||||
objectMetadataId: {
|
||||
metadataName: 'objectMetadata',
|
||||
flatEntityForeignKeyAggregator: 'indexMetadataIds',
|
||||
},
|
||||
},
|
||||
serverlessFunction: {},
|
||||
cronTrigger: {
|
||||
serverlessFunctionId: {
|
||||
metadataName: 'serverlessFunction',
|
||||
flatEntityForeignKeyAggregator: 'cronTriggerIds',
|
||||
},
|
||||
},
|
||||
databaseEventTrigger: {
|
||||
serverlessFunctionId: {
|
||||
metadataName: 'serverlessFunction',
|
||||
flatEntityForeignKeyAggregator: 'databaseEventTriggerIds',
|
||||
},
|
||||
},
|
||||
routeTrigger: {
|
||||
serverlessFunctionId: {
|
||||
metadataName: 'serverlessFunction',
|
||||
flatEntityForeignKeyAggregator: 'routeTriggerIds',
|
||||
},
|
||||
},
|
||||
viewFilter: {
|
||||
viewId: {
|
||||
metadataName: 'view',
|
||||
flatEntityForeignKeyAggregator: 'viewFilterIds',
|
||||
},
|
||||
fieldMetadataId: {
|
||||
metadataName: 'fieldMetadata',
|
||||
flatEntityForeignKeyAggregator: 'viewFilterIds',
|
||||
},
|
||||
viewFilterGroupId: {
|
||||
metadataName: 'viewFilterGroup',
|
||||
flatEntityForeignKeyAggregator: 'viewFilterIds',
|
||||
},
|
||||
},
|
||||
role: {},
|
||||
roleTarget: {
|
||||
roleId: {
|
||||
metadataName: 'role',
|
||||
flatEntityForeignKeyAggregator: 'roleTargetIds',
|
||||
},
|
||||
},
|
||||
agent: {},
|
||||
skill: {},
|
||||
pageLayout: {},
|
||||
pageLayoutWidget: {
|
||||
pageLayoutTabId: {
|
||||
metadataName: 'pageLayoutTab',
|
||||
flatEntityForeignKeyAggregator: 'widgetIds',
|
||||
},
|
||||
},
|
||||
pageLayoutTab: {
|
||||
pageLayoutId: {
|
||||
metadataName: 'pageLayout',
|
||||
flatEntityForeignKeyAggregator: 'tabIds',
|
||||
},
|
||||
},
|
||||
rowLevelPermissionPredicate: {},
|
||||
rowLevelPermissionPredicateGroup: {},
|
||||
viewFilterGroup: {
|
||||
viewId: {
|
||||
metadataName: 'view',
|
||||
flatEntityForeignKeyAggregator: 'viewFilterGroupIds',
|
||||
},
|
||||
parentViewFilterGroupId: {
|
||||
metadataName: 'viewFilterGroup',
|
||||
flatEntityForeignKeyAggregator: 'childViewFilterGroupIds',
|
||||
},
|
||||
},
|
||||
} as const satisfies MetadataNameAndRelations;
|
||||
-162
@@ -1,162 +0,0 @@
|
||||
import { type AllMetadataName } from 'twenty-shared/metadata';
|
||||
|
||||
import { type ExtractEntityRelatedEntityProperties } from 'src/engine/metadata-modules/flat-entity/types/extract-entity-related-entity-properties.type';
|
||||
import { type MetadataEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-entity.type';
|
||||
|
||||
export const ALL_METADATA_RELATION_PROPERTIES = {
|
||||
agent: {
|
||||
workspace: true,
|
||||
application: true,
|
||||
},
|
||||
skill: {
|
||||
workspace: true,
|
||||
application: true,
|
||||
},
|
||||
fieldMetadata: {
|
||||
relationTargetFieldMetadata: true,
|
||||
relationTargetObjectMetadata: true,
|
||||
fieldPermissions: true,
|
||||
indexFieldMetadatas: true,
|
||||
object: true,
|
||||
viewFields: true,
|
||||
viewFilters: true,
|
||||
kanbanAggregateOperationViews: true,
|
||||
calendarViews: true,
|
||||
mainGroupByFieldMetadataViews: true,
|
||||
workspace: true,
|
||||
application: true,
|
||||
},
|
||||
objectMetadata: {
|
||||
fields: true,
|
||||
indexMetadatas: true,
|
||||
targetRelationFields: true,
|
||||
dataSource: true,
|
||||
objectPermissions: true,
|
||||
fieldPermissions: true,
|
||||
views: true,
|
||||
workspace: true,
|
||||
application: true,
|
||||
},
|
||||
view: {
|
||||
objectMetadata: true,
|
||||
viewFields: true,
|
||||
viewFilters: true,
|
||||
viewFilterGroups: true,
|
||||
viewGroups: true,
|
||||
viewSorts: true,
|
||||
workspace: true,
|
||||
createdBy: true,
|
||||
application: true,
|
||||
calendarFieldMetadata: true,
|
||||
kanbanAggregateOperationFieldMetadata: true,
|
||||
mainGroupByFieldMetadata: true,
|
||||
},
|
||||
viewField: {
|
||||
fieldMetadata: true,
|
||||
view: true,
|
||||
workspace: true,
|
||||
application: true,
|
||||
},
|
||||
viewFilter: {
|
||||
fieldMetadata: true,
|
||||
view: true,
|
||||
viewFilterGroup: true,
|
||||
workspace: true,
|
||||
application: true,
|
||||
},
|
||||
viewGroup: {
|
||||
view: true,
|
||||
workspace: true,
|
||||
application: true,
|
||||
},
|
||||
index: {
|
||||
objectMetadata: true,
|
||||
indexFieldMetadatas: true,
|
||||
workspace: true,
|
||||
application: true,
|
||||
},
|
||||
serverlessFunction: {
|
||||
cronTriggers: true,
|
||||
databaseEventTriggers: true,
|
||||
routeTriggers: true,
|
||||
serverlessFunctionLayer: true,
|
||||
workspace: true,
|
||||
application: true,
|
||||
},
|
||||
cronTrigger: {
|
||||
serverlessFunction: true,
|
||||
workspace: true,
|
||||
application: true,
|
||||
},
|
||||
databaseEventTrigger: {
|
||||
serverlessFunction: true,
|
||||
workspace: true,
|
||||
application: true,
|
||||
},
|
||||
routeTrigger: {
|
||||
serverlessFunction: true,
|
||||
workspace: true,
|
||||
application: true,
|
||||
},
|
||||
role: {
|
||||
roleTargets: true,
|
||||
objectPermissions: true,
|
||||
permissionFlags: true,
|
||||
fieldPermissions: true,
|
||||
workspace: true,
|
||||
application: true,
|
||||
},
|
||||
roleTarget: {
|
||||
role: true,
|
||||
apiKey: true,
|
||||
workspace: true,
|
||||
application: true,
|
||||
},
|
||||
pageLayout: {
|
||||
workspace: true,
|
||||
objectMetadata: true,
|
||||
tabs: true,
|
||||
application: true,
|
||||
},
|
||||
pageLayoutTab: {
|
||||
workspace: true,
|
||||
pageLayout: true,
|
||||
widgets: true,
|
||||
application: true,
|
||||
},
|
||||
pageLayoutWidget: {
|
||||
workspace: true,
|
||||
pageLayoutTab: true,
|
||||
objectMetadata: true,
|
||||
application: true,
|
||||
},
|
||||
rowLevelPermissionPredicate: {
|
||||
workspace: true,
|
||||
role: true,
|
||||
fieldMetadata: true,
|
||||
workspaceMemberFieldMetadata: true,
|
||||
objectMetadata: true,
|
||||
rowLevelPermissionPredicateGroup: true,
|
||||
application: true,
|
||||
},
|
||||
rowLevelPermissionPredicateGroup: {
|
||||
workspace: true,
|
||||
role: true,
|
||||
parentRowLevelPermissionPredicateGroup: true,
|
||||
childRowLevelPermissionPredicateGroups: true,
|
||||
rowLevelPermissionPredicates: true,
|
||||
application: true,
|
||||
},
|
||||
viewFilterGroup: {
|
||||
view: true,
|
||||
viewFilters: true,
|
||||
parentViewFilterGroup: true,
|
||||
childViewFilterGroups: true,
|
||||
workspace: true,
|
||||
application: true,
|
||||
},
|
||||
} as const satisfies {
|
||||
[TName in AllMetadataName]: {
|
||||
[P in ExtractEntityRelatedEntityProperties<MetadataEntity<TName>>]: true;
|
||||
};
|
||||
};
|
||||
+436
@@ -0,0 +1,436 @@
|
||||
import { type AllMetadataName } from 'twenty-shared/metadata';
|
||||
import { type Expect } from 'twenty-shared/testing';
|
||||
import {
|
||||
type ExtractPropertiesThatEndsWithId,
|
||||
type ExtractPropertiesThatEndsWithIds,
|
||||
} from 'twenty-shared/types';
|
||||
import { type Relation } from 'typeorm';
|
||||
|
||||
import { type ExtractEntityManyToOneEntityRelationProperties } from 'src/engine/metadata-modules/flat-entity/types/extract-entity-many-to-one-entity-relation-properties.type';
|
||||
import { type ExtractEntityOneToManyEntityRelationProperties } from 'src/engine/metadata-modules/flat-entity/types/extract-entity-one-to-many-entity-relation-properties.type';
|
||||
import { type FromMetadataEntityToMetadataName } from 'src/engine/metadata-modules/flat-entity/types/from-metadata-entity-to-metadata-name.type';
|
||||
import { type MetadataEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-entity.type';
|
||||
import { type MetadataFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity.type';
|
||||
import { type SyncableEntity } from 'src/engine/workspace-manager/workspace-sync/types/syncable-entity.interface';
|
||||
|
||||
type ManyToOneRelationValue<
|
||||
TSourceMetadataName extends AllMetadataName,
|
||||
TRelationProperty extends ExtractEntityManyToOneEntityRelationProperties<
|
||||
MetadataEntity<TSourceMetadataName>
|
||||
>,
|
||||
> =
|
||||
NonNullable<
|
||||
MetadataEntity<TSourceMetadataName>[TRelationProperty]
|
||||
> extends Relation<infer TTargetEntity extends SyncableEntity>
|
||||
? {
|
||||
metadataName: FromMetadataEntityToMetadataName<TTargetEntity>;
|
||||
flatEntityForeignKeyAggregator: ExtractPropertiesThatEndsWithIds<
|
||||
MetadataFlatEntity<FromMetadataEntityToMetadataName<TTargetEntity>>
|
||||
// Note: In the best of the world should not be nullable, entities should always declare inverside keys
|
||||
> | null;
|
||||
foreignKey: ExtractPropertiesThatEndsWithId<
|
||||
MetadataFlatEntity<TSourceMetadataName>,
|
||||
'id' | 'workspaceId'
|
||||
>;
|
||||
}
|
||||
: null;
|
||||
|
||||
type OneToManyRelationValue<
|
||||
TSourceMetadataName extends AllMetadataName,
|
||||
TRelationProperty extends ExtractEntityOneToManyEntityRelationProperties<
|
||||
MetadataEntity<TSourceMetadataName>
|
||||
>,
|
||||
> =
|
||||
MetadataEntity<TSourceMetadataName>[TRelationProperty] extends Relation<
|
||||
(infer TTargetEntity extends SyncableEntity)[]
|
||||
>
|
||||
? {
|
||||
metadataName: FromMetadataEntityToMetadataName<TTargetEntity>;
|
||||
}
|
||||
: null;
|
||||
|
||||
type MetadataRelationsProperties = {
|
||||
[TSourceMetadataName in AllMetadataName]: {
|
||||
manyToOne: {
|
||||
[TRelationProperty in ExtractEntityManyToOneEntityRelationProperties<
|
||||
MetadataEntity<TSourceMetadataName>
|
||||
>]: ManyToOneRelationValue<TSourceMetadataName, TRelationProperty>;
|
||||
};
|
||||
oneToMany: {
|
||||
[TRelationProperty in ExtractEntityOneToManyEntityRelationProperties<
|
||||
MetadataEntity<TSourceMetadataName>
|
||||
>]: OneToManyRelationValue<TSourceMetadataName, TRelationProperty>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export const ALL_METADATA_RELATIONS = {
|
||||
agent: {
|
||||
manyToOne: {
|
||||
workspace: null,
|
||||
application: null,
|
||||
},
|
||||
oneToMany: {},
|
||||
},
|
||||
skill: {
|
||||
manyToOne: {
|
||||
workspace: null,
|
||||
application: null,
|
||||
},
|
||||
oneToMany: {},
|
||||
},
|
||||
fieldMetadata: {
|
||||
manyToOne: {
|
||||
object: {
|
||||
metadataName: 'objectMetadata',
|
||||
flatEntityForeignKeyAggregator: 'fieldMetadataIds',
|
||||
foreignKey: 'objectMetadataId',
|
||||
},
|
||||
workspace: null,
|
||||
application: null,
|
||||
relationTargetFieldMetadata: {
|
||||
metadataName: 'fieldMetadata',
|
||||
flatEntityForeignKeyAggregator: null,
|
||||
foreignKey: 'relationTargetFieldMetadataId',
|
||||
},
|
||||
relationTargetObjectMetadata: {
|
||||
metadataName: 'objectMetadata',
|
||||
flatEntityForeignKeyAggregator: null,
|
||||
foreignKey: 'relationTargetObjectMetadataId',
|
||||
},
|
||||
},
|
||||
oneToMany: {
|
||||
fieldPermissions: null,
|
||||
indexFieldMetadatas: null,
|
||||
viewFields: { metadataName: 'viewField' },
|
||||
viewFilters: { metadataName: 'viewFilter' },
|
||||
kanbanAggregateOperationViews: { metadataName: 'view' },
|
||||
calendarViews: { metadataName: 'view' },
|
||||
mainGroupByFieldMetadataViews: { metadataName: 'view' },
|
||||
},
|
||||
},
|
||||
objectMetadata: {
|
||||
manyToOne: {
|
||||
dataSource: null,
|
||||
workspace: null,
|
||||
application: null,
|
||||
},
|
||||
oneToMany: {
|
||||
fields: { metadataName: 'fieldMetadata' },
|
||||
indexMetadatas: { metadataName: 'index' },
|
||||
targetRelationFields: { metadataName: 'fieldMetadata' },
|
||||
objectPermissions: null,
|
||||
fieldPermissions: null,
|
||||
views: { metadataName: 'view' },
|
||||
},
|
||||
},
|
||||
view: {
|
||||
manyToOne: {
|
||||
objectMetadata: {
|
||||
foreignKey: 'objectMetadataId',
|
||||
metadataName: 'objectMetadata',
|
||||
flatEntityForeignKeyAggregator: 'viewIds',
|
||||
},
|
||||
workspace: null,
|
||||
createdBy: null,
|
||||
application: null,
|
||||
calendarFieldMetadata: {
|
||||
foreignKey: 'calendarFieldMetadataId',
|
||||
metadataName: 'fieldMetadata',
|
||||
flatEntityForeignKeyAggregator: 'calendarViewIds',
|
||||
},
|
||||
kanbanAggregateOperationFieldMetadata: {
|
||||
foreignKey: 'kanbanAggregateOperationFieldMetadataId',
|
||||
metadataName: 'fieldMetadata',
|
||||
flatEntityForeignKeyAggregator: 'kanbanAggregateOperationViewIds',
|
||||
},
|
||||
mainGroupByFieldMetadata: {
|
||||
foreignKey: 'mainGroupByFieldMetadataId',
|
||||
metadataName: 'fieldMetadata',
|
||||
flatEntityForeignKeyAggregator: 'mainGroupByFieldMetadataViewIds',
|
||||
},
|
||||
},
|
||||
oneToMany: {
|
||||
viewFields: { metadataName: 'viewField' },
|
||||
viewFilters: { metadataName: 'viewFilter' },
|
||||
viewFilterGroups: {
|
||||
metadataName: 'viewFilterGroup',
|
||||
},
|
||||
viewGroups: { metadataName: 'viewGroup' },
|
||||
// @ts-expect-error TODO migrate viewSort to v2
|
||||
viewSorts: null,
|
||||
},
|
||||
},
|
||||
viewField: {
|
||||
manyToOne: {
|
||||
fieldMetadata: {
|
||||
metadataName: 'fieldMetadata',
|
||||
flatEntityForeignKeyAggregator: 'viewFieldIds',
|
||||
foreignKey: 'fieldMetadataId',
|
||||
},
|
||||
view: {
|
||||
metadataName: 'view',
|
||||
flatEntityForeignKeyAggregator: 'viewFieldIds',
|
||||
foreignKey: 'viewId',
|
||||
},
|
||||
workspace: null,
|
||||
application: null,
|
||||
},
|
||||
oneToMany: {},
|
||||
},
|
||||
viewFilter: {
|
||||
manyToOne: {
|
||||
fieldMetadata: {
|
||||
metadataName: 'fieldMetadata',
|
||||
flatEntityForeignKeyAggregator: 'viewFilterIds',
|
||||
foreignKey: 'fieldMetadataId',
|
||||
},
|
||||
view: {
|
||||
metadataName: 'view',
|
||||
flatEntityForeignKeyAggregator: 'viewFilterIds',
|
||||
foreignKey: 'viewId',
|
||||
},
|
||||
viewFilterGroup: {
|
||||
flatEntityForeignKeyAggregator: 'viewFilterIds',
|
||||
foreignKey: 'viewFilterGroupId',
|
||||
metadataName: 'viewFilterGroup',
|
||||
},
|
||||
workspace: null,
|
||||
application: null,
|
||||
},
|
||||
oneToMany: {},
|
||||
},
|
||||
viewGroup: {
|
||||
manyToOne: {
|
||||
view: {
|
||||
metadataName: 'view',
|
||||
flatEntityForeignKeyAggregator: 'viewGroupIds',
|
||||
foreignKey: 'viewId',
|
||||
},
|
||||
workspace: null,
|
||||
application: null,
|
||||
},
|
||||
oneToMany: {},
|
||||
},
|
||||
index: {
|
||||
manyToOne: {
|
||||
objectMetadata: {
|
||||
metadataName: 'objectMetadata',
|
||||
flatEntityForeignKeyAggregator: 'indexMetadataIds',
|
||||
foreignKey: 'objectMetadataId',
|
||||
},
|
||||
workspace: null,
|
||||
application: null,
|
||||
},
|
||||
oneToMany: {
|
||||
indexFieldMetadatas: null,
|
||||
},
|
||||
},
|
||||
serverlessFunction: {
|
||||
manyToOne: {
|
||||
workspace: null,
|
||||
application: null,
|
||||
serverlessFunctionLayer: null,
|
||||
},
|
||||
oneToMany: {
|
||||
cronTriggers: { metadataName: 'cronTrigger' },
|
||||
databaseEventTriggers: { metadataName: 'databaseEventTrigger' },
|
||||
routeTriggers: { metadataName: 'routeTrigger' },
|
||||
},
|
||||
},
|
||||
cronTrigger: {
|
||||
manyToOne: {
|
||||
serverlessFunction: {
|
||||
metadataName: 'serverlessFunction',
|
||||
flatEntityForeignKeyAggregator: 'cronTriggerIds',
|
||||
foreignKey: 'serverlessFunctionId',
|
||||
},
|
||||
workspace: null,
|
||||
application: null,
|
||||
},
|
||||
oneToMany: {},
|
||||
},
|
||||
databaseEventTrigger: {
|
||||
manyToOne: {
|
||||
serverlessFunction: {
|
||||
metadataName: 'serverlessFunction',
|
||||
flatEntityForeignKeyAggregator: 'databaseEventTriggerIds',
|
||||
foreignKey: 'serverlessFunctionId',
|
||||
},
|
||||
workspace: null,
|
||||
application: null,
|
||||
},
|
||||
oneToMany: {},
|
||||
},
|
||||
routeTrigger: {
|
||||
manyToOne: {
|
||||
serverlessFunction: {
|
||||
metadataName: 'serverlessFunction',
|
||||
flatEntityForeignKeyAggregator: 'routeTriggerIds',
|
||||
foreignKey: 'serverlessFunctionId',
|
||||
},
|
||||
workspace: null,
|
||||
application: null,
|
||||
},
|
||||
oneToMany: {},
|
||||
},
|
||||
role: {
|
||||
manyToOne: {
|
||||
workspace: null,
|
||||
application: null,
|
||||
},
|
||||
oneToMany: {
|
||||
roleTargets: { metadataName: 'roleTarget' },
|
||||
objectPermissions: null,
|
||||
permissionFlags: null,
|
||||
fieldPermissions: null,
|
||||
},
|
||||
},
|
||||
roleTarget: {
|
||||
manyToOne: {
|
||||
role: {
|
||||
metadataName: 'role',
|
||||
flatEntityForeignKeyAggregator: 'roleTargetIds',
|
||||
foreignKey: 'roleId',
|
||||
},
|
||||
apiKey: null,
|
||||
workspace: null,
|
||||
application: null,
|
||||
},
|
||||
oneToMany: {},
|
||||
},
|
||||
pageLayout: {
|
||||
manyToOne: {
|
||||
workspace: null,
|
||||
objectMetadata: {
|
||||
metadataName: 'objectMetadata',
|
||||
flatEntityForeignKeyAggregator: null,
|
||||
foreignKey: 'objectMetadataId',
|
||||
},
|
||||
application: null,
|
||||
},
|
||||
oneToMany: {
|
||||
tabs: { metadataName: 'pageLayoutTab' },
|
||||
},
|
||||
},
|
||||
pageLayoutTab: {
|
||||
manyToOne: {
|
||||
workspace: null,
|
||||
pageLayout: {
|
||||
metadataName: 'pageLayout',
|
||||
flatEntityForeignKeyAggregator: 'tabIds',
|
||||
foreignKey: 'pageLayoutId',
|
||||
},
|
||||
application: null,
|
||||
},
|
||||
oneToMany: {
|
||||
widgets: { metadataName: 'pageLayoutWidget' },
|
||||
},
|
||||
},
|
||||
pageLayoutWidget: {
|
||||
manyToOne: {
|
||||
workspace: null,
|
||||
pageLayoutTab: {
|
||||
metadataName: 'pageLayoutTab',
|
||||
flatEntityForeignKeyAggregator: 'widgetIds',
|
||||
foreignKey: 'pageLayoutTabId',
|
||||
},
|
||||
objectMetadata: {
|
||||
metadataName: 'objectMetadata',
|
||||
flatEntityForeignKeyAggregator: null,
|
||||
foreignKey: 'objectMetadataId',
|
||||
},
|
||||
application: null,
|
||||
},
|
||||
oneToMany: {},
|
||||
},
|
||||
rowLevelPermissionPredicate: {
|
||||
manyToOne: {
|
||||
workspace: null,
|
||||
role: {
|
||||
metadataName: 'role',
|
||||
flatEntityForeignKeyAggregator: null,
|
||||
foreignKey: 'roleId',
|
||||
},
|
||||
fieldMetadata: {
|
||||
metadataName: 'fieldMetadata',
|
||||
flatEntityForeignKeyAggregator: null,
|
||||
foreignKey: 'fieldMetadataId',
|
||||
},
|
||||
workspaceMemberFieldMetadata: {
|
||||
metadataName: 'fieldMetadata',
|
||||
flatEntityForeignKeyAggregator: null,
|
||||
foreignKey: 'workspaceMemberFieldMetadataId',
|
||||
},
|
||||
objectMetadata: {
|
||||
metadataName: 'objectMetadata',
|
||||
flatEntityForeignKeyAggregator: null,
|
||||
foreignKey: 'objectMetadataId',
|
||||
},
|
||||
rowLevelPermissionPredicateGroup: {
|
||||
metadataName: 'rowLevelPermissionPredicateGroup',
|
||||
flatEntityForeignKeyAggregator: null,
|
||||
foreignKey: 'rowLevelPermissionPredicateGroupId',
|
||||
},
|
||||
application: null,
|
||||
},
|
||||
oneToMany: {},
|
||||
},
|
||||
rowLevelPermissionPredicateGroup: {
|
||||
manyToOne: {
|
||||
workspace: null,
|
||||
role: {
|
||||
metadataName: 'role',
|
||||
foreignKey: 'roleId',
|
||||
flatEntityForeignKeyAggregator: null,
|
||||
},
|
||||
parentRowLevelPermissionPredicateGroup: {
|
||||
metadataName: 'rowLevelPermissionPredicateGroup',
|
||||
foreignKey: 'parentRowLevelPermissionPredicateGroupId',
|
||||
flatEntityForeignKeyAggregator:
|
||||
'childRowLevelPermissionPredicateGroupIds',
|
||||
},
|
||||
application: null,
|
||||
},
|
||||
oneToMany: {
|
||||
childRowLevelPermissionPredicateGroups: {
|
||||
metadataName: 'rowLevelPermissionPredicateGroup',
|
||||
},
|
||||
rowLevelPermissionPredicates: {
|
||||
metadataName: 'rowLevelPermissionPredicate',
|
||||
},
|
||||
},
|
||||
},
|
||||
viewFilterGroup: {
|
||||
manyToOne: {
|
||||
application: null,
|
||||
parentViewFilterGroup: {
|
||||
flatEntityForeignKeyAggregator: 'childViewFilterGroupIds',
|
||||
foreignKey: 'parentViewFilterGroupId',
|
||||
metadataName: 'viewFilterGroup',
|
||||
},
|
||||
view: {
|
||||
metadataName: 'view',
|
||||
flatEntityForeignKeyAggregator: 'viewFilterGroupIds',
|
||||
foreignKey: 'viewId',
|
||||
},
|
||||
workspace: null,
|
||||
},
|
||||
oneToMany: {
|
||||
childViewFilterGroups: {
|
||||
metadataName: 'viewFilterGroup',
|
||||
},
|
||||
viewFilters: {
|
||||
metadataName: 'viewFilter',
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const satisfies MetadataRelationsProperties;
|
||||
|
||||
// Note: satisfies with complex mapped types involving nested generics doesn't always catch missing required keys
|
||||
// eslint-disable-next-line unused-imports/no-unused-vars
|
||||
type Assertions = [
|
||||
Expect<
|
||||
AllMetadataName extends keyof typeof ALL_METADATA_RELATIONS ? true : false
|
||||
>,
|
||||
];
|
||||
+5
-3
@@ -4,7 +4,7 @@ import { type MetadataManyToOneRelatedMetadataNames } from 'src/engine/metadata-
|
||||
|
||||
type MetadataRequiredForValidation = {
|
||||
[T in AllMetadataName]: Record<
|
||||
MetadataManyToOneRelatedMetadataNames<T>,
|
||||
Exclude<MetadataManyToOneRelatedMetadataNames<T>, T>,
|
||||
true
|
||||
> & {
|
||||
[K in Exclude<AllMetadataName, T>]?: true;
|
||||
@@ -52,7 +52,6 @@ export const ALL_METADATA_REQUIRED_METADATA_FOR_VALIDATION = {
|
||||
},
|
||||
viewFilterGroup: {
|
||||
view: true,
|
||||
viewFilterGroup: true,
|
||||
},
|
||||
role: {},
|
||||
roleTarget: {
|
||||
@@ -63,11 +62,14 @@ export const ALL_METADATA_REQUIRED_METADATA_FOR_VALIDATION = {
|
||||
role: true,
|
||||
},
|
||||
skill: {},
|
||||
pageLayout: {},
|
||||
pageLayout: {
|
||||
objectMetadata: true,
|
||||
},
|
||||
pageLayoutTab: {
|
||||
pageLayout: true,
|
||||
},
|
||||
pageLayoutWidget: {
|
||||
objectMetadata: true,
|
||||
pageLayoutTab: true,
|
||||
},
|
||||
rowLevelPermissionPredicate: {
|
||||
|
||||
Reference in New Issue
Block a user