Skip to content

Commit

Permalink
fix: error
Browse files Browse the repository at this point in the history
  • Loading branch information
alban bertolini committed Oct 2, 2024
1 parent 5484cec commit d66b91e
Show file tree
Hide file tree
Showing 22 changed files with 132 additions and 93 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ export default class OperatorsEmulateCollectionDecorator extends CollectionDecor
// Check that the collection can actually support our rewriting
const pks = SchemaUtils.getPrimaryKeys(this.childCollection.schema);
pks.forEach(pk => {
const schema = SchemaUtils.getColumn(
const schema = SchemaUtils.getField(
this.childCollection.schema,
pk,
this.childCollection.name,
);
) as ColumnSchema;
const operators = schema.filterOperators;

if (!operators?.has('Equal') || !operators?.has('In')) {
Expand All @@ -55,13 +55,8 @@ export default class OperatorsEmulateCollectionDecorator extends CollectionDecor
});

// Check that targeted field is valid
const field = SchemaUtils.getColumn(
this.childCollection.schema,
name,
this.childCollection.name,
);
SchemaUtils.throwIfMissingField(this.childCollection.schema, name, this.childCollection.name);
FieldValidator.validate(this, name);
if (!field) throw new Error('Cannot replace operator for relation');

// Mark the field operator as replaced.
if (!this.fields.has(name)) this.fields.set(name, new Map());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */

import { ColumnSchema, ConditionTreeLeaf, Sort } from '@forestadmin/datasource-toolkit';
import {
ColumnSchema,
ConditionTreeLeaf,
MissingFieldError,
Sort,
} from '@forestadmin/datasource-toolkit';
import * as factories from '@forestadmin/datasource-toolkit/dist/test/__factories__';

import {
Expand Down Expand Up @@ -322,9 +327,7 @@ describe('Builder > Collection', () => {
const { dsc, customizer } = await setup();

customizer.importField('translatorName', { path: 'doesNotExistPath' });
await expect(dsc.getDataSource(logger)).rejects.toThrow(
new MissingFieldError('doesNotExistPath', 'authors'),
);
await expect(dsc.getDataSource(logger)).rejects.toThrow(MissingFieldError);
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
Collection,
DataSource,
DataSourceDecorator,
MissingFieldError,
PaginatedFilter,
Projection,
} from '@forestadmin/datasource-toolkit';
Expand Down Expand Up @@ -102,7 +103,7 @@ describe('ComputedDecorator', () => {
dependencies: ['__nonExisting__'],
getValues: () => Promise.reject(),
});
}).toThrow(new MissingFieldError('__nonExisting__', 'books'));
}).toThrow(MissingFieldError);
});

test('should throw if defining a field with invalid dependencies', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import {
ConditionTreeLeaf,
DataSource,
DataSourceDecorator,
MissingFieldError,
PaginatedFilter,
Projection,
RecordData,
RelationFieldAccessDeniedError,
} from '@forestadmin/datasource-toolkit';
import * as factories from '@forestadmin/datasource-toolkit/dist/test/__factories__';

Expand Down Expand Up @@ -115,7 +117,7 @@ describe('OperatorsEmulateCollectionDecorator', () => {

test('emulateFieldOperator() should throw if the field does not exists', () => {
expect(() => newBooks.emulateFieldOperator('__dontExist', 'Equal')).toThrow(
new MissingFieldError('__dontExist', 'books'),
MissingFieldError,
);
});

Expand All @@ -127,7 +129,7 @@ describe('OperatorsEmulateCollectionDecorator', () => {

test('emulateFieldOperator() should throw if the field is in a relation', () => {
expect(() => newBooks.emulateFieldOperator('author:firstName', 'Equal')).toThrow(
'Cannot replace operator for relation',
RelationFieldAccessDeniedError,
);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,7 @@ describe('PublicationCollectionDecorator', () => {
});

test('should throw when hiding a field which does not exists', () => {
expect(() => newPersons.changeFieldVisibility('unknown', false)).toThrow(
new MissingFieldError('unknown', 'persons'),
);
expect(() => newPersons.changeFieldVisibility('unknown', false)).toThrow(MissingFieldError);
});

test('should throw when hiding the primary key', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
DataSourceDecorator,
Filter,
ManyToManySchema,
MissingColumnError,
MissingFieldError,
PaginatedFilter,
Projection,
Sort,
Expand Down Expand Up @@ -165,7 +167,7 @@ describe('RelationCollectionDecorator', () => {
foreignCollection: 'passports',
originKey: '__nonExisting__',
}),
).toThrow(new MissingFieldError('__nonExisting__', 'passports'));
).toThrow(MissingColumnError);
});
});

Expand Down Expand Up @@ -282,7 +284,7 @@ describe('RelationCollectionDecorator', () => {
foreignCollection: 'persons',
foreignKey: '__nonExisting__',
}),
).toThrow(new MissingFieldError('__nonExisting__', 'passports'));
).toThrow(MissingFieldError);
});
});

Expand Down Expand Up @@ -350,7 +352,7 @@ describe('RelationCollectionDecorator', () => {
originKey: '__nonExisting__',
throughCollection: 'passports',
} as ManyToManySchema),
).toThrow(new MissingFieldError('__nonExisting__', 'passports'));
).toThrow(MissingFieldError);
});

test('should throw with a non existent fk', () => {
Expand All @@ -362,7 +364,7 @@ describe('RelationCollectionDecorator', () => {
originKey: 'ownerId',
throughCollection: 'passports',
} as ManyToManySchema),
).toThrow(new MissingFieldError('__nonExisting__', 'passports'));
).toThrow(MissingFieldError);
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
DataSource,
DataSourceDecorator,
Filter,
MissingFieldError,
PaginatedFilter,
Projection,
Sort,
Expand Down Expand Up @@ -130,14 +131,12 @@ describe('RenameFieldCollectionDecorator', () => {
});

test('should throw when renaming a field which does not exists', () => {
expect(() => newPersons.renameField('unknown', 'somethingnew')).toThrow(
new MissingFieldError('unknown'),
);
expect(() => newPersons.renameField('unknown', 'somethingnew')).toThrow(MissingFieldError);
});

test('should throw when renaming a field using an older name', () => {
newPersons.renameField('id', 'key');
expect(() => newPersons.renameField('id', 'primaryKey')).toThrow(new MissingFieldError('id'));
expect(() => newPersons.renameField('id', 'primaryKey')).toThrow(MissingFieldError);
});

test('should throw when renaming with a name including space', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Collection, DataSource } from '@forestadmin/datasource-toolkit';
import { Collection, DataSource, MissingFieldError } from '@forestadmin/datasource-toolkit';
import * as factories from '@forestadmin/datasource-toolkit/dist/test/__factories__';

import SegmentCollectionDecorator from '../../../src/decorators/segment/collection';
Expand Down Expand Up @@ -102,9 +102,7 @@ describe('SegmentCollectionDecorator', () => {
factories.caller.build(),
factories.filter.build({ segment: 'segmentName' }),
),
).rejects.toThrow(
"The 'books.do not exists' field was not found. Available fields are: [name]. Please check if the field name is correct.",
);
).rejects.toThrow(MissingFieldError);

expect(conditionTreeGenerator).toHaveBeenCalled();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
ColumnSchema,
DataSource,
DataSourceDecorator,
MissingFieldError,
Page,
PaginatedFilter,
Projection,
Expand Down Expand Up @@ -93,9 +94,7 @@ describe('SortEmulationDecoratorCollection', () => {
});

test('emulateFieldSorting() should throw if the field does not exists', () => {
expect(() => newBooks.emulateFieldSorting('__dontExist')).toThrow(
new MissingFieldError('__dontExist', 'books'),
);
expect(() => newBooks.emulateFieldSorting('__dontExist')).toThrow(MissingFieldError);
});

test('emulateFieldSorting() should throw if the field is a relation', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { Collection, DataSource, DataSourceDecorator } from '@forestadmin/datasource-toolkit';
import {
Collection,
DataSource,
DataSourceDecorator,
MissingFieldError,
RelationFieldAccessDeniedError,
} from '@forestadmin/datasource-toolkit';
import * as factories from '@forestadmin/datasource-toolkit/dist/test/__factories__';

import ValidationDecorator from '../../../src/decorators/validation/collection';
Expand Down Expand Up @@ -49,7 +55,7 @@ describe('SortEmulationDecoratorCollection', () => {

test('addValidation() should throw if the field does not exists', () => {
expect(() => newBooks.addValidation('__dontExist', { operator: 'Present' })).toThrow(
new MissingFieldError('__dontExist', 'books'),
MissingFieldError,
);
});

Expand All @@ -67,7 +73,7 @@ describe('SortEmulationDecoratorCollection', () => {

test('addValidation() should throw if the field is in a relation', () => {
expect(() => newBooks.addValidation('author:firstName', { operator: 'Present' })).toThrow(
'Cannot add validators on a relation, use the foreign key instead',
RelationFieldAccessDeniedError,
);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ describe('WriteDecorator > When their are no relations', () => {
const decorator = new WriteDecorator(collection, dataSource);

expect(() => decorator.replaceFieldWriting('inexistant', () => ({}))).toThrow(
new MissingFieldError('inexistant', 'books'),
MissingFieldError,
);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,6 @@ describe('importField', () => {
path: 'INVALID',
name: 'NOPE',
}),
).rejects.toThrow(new MissingFieldError('INVALID', 'collection1'));
).rejects.toThrow(MissingFieldError);
});
});
57 changes: 46 additions & 11 deletions packages/datasource-toolkit/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,26 +77,61 @@ export class MissingSchemaElementError extends ValidationError {}

export class MissingCollectionError extends MissingSchemaElementError {}

export class MissingFieldError extends MissingSchemaElementError {
constructor(options: {
typeOfField: 'Field' | 'Relation' | 'Column';
fieldName: string;
availableFields: string[];
collectionName?: string;
}) {
const { typeOfField, fieldName, availableFields, collectionName } = options;
const path = collectionName ? `${collectionName}.${fieldName}` : fieldName;
function buildPath(fieldName: string, collectionName?: string): string {
return collectionName ? `${collectionName}.${fieldName}` : fieldName;
}

type MissingFieldErrorOptions = {
fieldName: string;
availableFields: string[];
collectionName?: string;
};

function buildMessageMissingElement(options: {
typeOfField: 'Field' | 'Column' | 'Relation';
fieldName: string;
availableFields: string[];
collectionName?: string;
}): string {
const { typeOfField, fieldName, availableFields, collectionName } = options;
const path = buildPath(fieldName, collectionName);

return `The '${path}' ${typeOfField.toLowerCase()} was not found. Available ${typeOfField.toLowerCase()}s are: [${availableFields}]. Please check if the ${typeOfField.toLowerCase()} name is correct.`;
}

export class RelationFieldAccessDeniedError extends ValidationError {
constructor(options: Pick<MissingFieldErrorOptions, 'fieldName' | 'collectionName'>) {
const { fieldName, collectionName } = options;
const path = buildPath(fieldName, collectionName);

super(
`The '${path}' ${typeOfField.toLowerCase()} was not found. Available ${typeOfField.toLowerCase()}s are: [${availableFields}]. Please check if the ${typeOfField.toLowerCase()} name is correct.`,
`Access to the '${path}' field is denied. You are trying to access a field from a related entity, but this is not allowed in the current context. Please verify the field name and context of use.`,
);
}
}

export class MissingFieldError extends MissingSchemaElementError {
constructor(options: MissingFieldErrorOptions) {
super(buildMessageMissingElement({ typeOfField: 'Field', ...options }));
}
}

export class MissingColumnError extends MissingSchemaElementError {
constructor(options: MissingFieldErrorOptions) {
super(buildMessageMissingElement({ typeOfField: 'Column', ...options }));
}
}

export class MissingRelationError extends MissingSchemaElementError {
constructor(options: MissingFieldErrorOptions) {
super(buildMessageMissingElement({ typeOfField: 'Relation', ...options }));
}
}

export class AlreadyDefinedFieldError extends ValidationError {
constructor(options: { fieldName: string; collectionName?: string }) {
const { fieldName, collectionName } = options;
const path = collectionName ? `${collectionName}.${fieldName}` : fieldName;
const path = buildPath(fieldName, collectionName);

super(
`The '${path}' field is already defined. Please check if the field name is correct and unique.`,
Expand Down
Loading

0 comments on commit d66b91e

Please sign in to comment.