feat: add default filter types (#2087)
* feat: add default filter types * fix: fields doesn't need to be a function
This commit is contained in:
@ -0,0 +1,22 @@
|
||||
import {
|
||||
GraphQLInputObjectType,
|
||||
GraphQLList,
|
||||
GraphQLNonNull,
|
||||
GraphQLFloat,
|
||||
} from 'graphql';
|
||||
|
||||
import { FilterIsEnumType } from './filter-is-enum-filter.type';
|
||||
|
||||
export const BigFloatFilterType = new GraphQLInputObjectType({
|
||||
name: 'BigFloatType',
|
||||
fields: {
|
||||
eq: { type: GraphQLFloat },
|
||||
gt: { type: GraphQLFloat },
|
||||
gte: { type: GraphQLFloat },
|
||||
in: { type: new GraphQLList(new GraphQLNonNull(GraphQLFloat)) },
|
||||
lt: { type: GraphQLFloat },
|
||||
lte: { type: GraphQLFloat },
|
||||
neq: { type: GraphQLFloat },
|
||||
is: { type: FilterIsEnumType },
|
||||
},
|
||||
});
|
||||
@ -0,0 +1,22 @@
|
||||
import {
|
||||
GraphQLInputObjectType,
|
||||
GraphQLList,
|
||||
GraphQLNonNull,
|
||||
GraphQLInt,
|
||||
} from 'graphql';
|
||||
|
||||
import { FilterIsEnumType } from './filter-is-enum-filter.type';
|
||||
|
||||
export const BigIntFilterType = new GraphQLInputObjectType({
|
||||
name: 'BigIntFilter',
|
||||
fields: {
|
||||
eq: { type: GraphQLInt },
|
||||
gt: { type: GraphQLInt },
|
||||
gte: { type: GraphQLInt },
|
||||
in: { type: new GraphQLList(new GraphQLNonNull(GraphQLInt)) },
|
||||
lt: { type: GraphQLInt },
|
||||
lte: { type: GraphQLInt },
|
||||
neq: { type: GraphQLInt },
|
||||
is: { type: FilterIsEnumType },
|
||||
},
|
||||
});
|
||||
@ -0,0 +1,19 @@
|
||||
import { GraphQLInputObjectType, GraphQLList, GraphQLNonNull } from 'graphql';
|
||||
|
||||
import { DateScalarType } from 'src/tenant/schema-builder/graphql-types/scalars/date.scalar';
|
||||
|
||||
import { FilterIsEnumType } from './filter-is-enum-filter.type';
|
||||
|
||||
export const DateFilterType = new GraphQLInputObjectType({
|
||||
name: 'DateFilter',
|
||||
fields: {
|
||||
eq: { type: DateScalarType },
|
||||
gt: { type: DateScalarType },
|
||||
gte: { type: DateScalarType },
|
||||
in: { type: new GraphQLList(new GraphQLNonNull(DateScalarType)) },
|
||||
lt: { type: DateScalarType },
|
||||
lte: { type: DateScalarType },
|
||||
neq: { type: DateScalarType },
|
||||
is: { type: FilterIsEnumType },
|
||||
},
|
||||
});
|
||||
@ -0,0 +1,19 @@
|
||||
import { GraphQLInputObjectType, GraphQLList, GraphQLNonNull } from 'graphql';
|
||||
|
||||
import { DatetimeScalarType } from 'src/tenant/schema-builder/graphql-types/scalars/datetime.scalar';
|
||||
|
||||
import { FilterIsEnumType } from './filter-is-enum-filter.type';
|
||||
|
||||
export const DatetimeFilterInputType = new GraphQLInputObjectType({
|
||||
name: 'DatetimeFilter',
|
||||
fields: {
|
||||
eq: { type: DatetimeScalarType },
|
||||
gt: { type: DatetimeScalarType },
|
||||
gte: { type: DatetimeScalarType },
|
||||
in: { type: new GraphQLList(new GraphQLNonNull(DatetimeScalarType)) },
|
||||
lt: { type: DatetimeScalarType },
|
||||
lte: { type: DatetimeScalarType },
|
||||
neq: { type: DatetimeScalarType },
|
||||
is: { type: FilterIsEnumType },
|
||||
},
|
||||
});
|
||||
@ -0,0 +1,9 @@
|
||||
import { GraphQLEnumType } from 'graphql';
|
||||
|
||||
export const FilterIsEnumType = new GraphQLEnumType({
|
||||
name: 'FilterIs',
|
||||
values: {
|
||||
PENDING: { value: 'PENDING' },
|
||||
RELEASED: { value: 'RELEASED' },
|
||||
},
|
||||
});
|
||||
@ -0,0 +1,22 @@
|
||||
import {
|
||||
GraphQLInputObjectType,
|
||||
GraphQLFloat,
|
||||
GraphQLList,
|
||||
GraphQLNonNull,
|
||||
} from 'graphql';
|
||||
|
||||
import { FilterIsEnumType } from './filter-is-enum-filter.type';
|
||||
|
||||
export const FloatFilter = new GraphQLInputObjectType({
|
||||
name: 'FloatFilter',
|
||||
fields: {
|
||||
eq: { type: GraphQLFloat },
|
||||
gt: { type: GraphQLFloat },
|
||||
gte: { type: GraphQLFloat },
|
||||
in: { type: new GraphQLList(new GraphQLNonNull(GraphQLFloat)) },
|
||||
lt: { type: GraphQLFloat },
|
||||
lte: { type: GraphQLFloat },
|
||||
neq: { type: GraphQLFloat },
|
||||
is: { type: FilterIsEnumType },
|
||||
},
|
||||
});
|
||||
@ -0,0 +1,22 @@
|
||||
import {
|
||||
GraphQLInputObjectType,
|
||||
GraphQLList,
|
||||
GraphQLNonNull,
|
||||
GraphQLInt,
|
||||
} from 'graphql';
|
||||
|
||||
import { FilterIsEnumType } from './filter-is-enum-filter.type';
|
||||
|
||||
export const IntFilter = new GraphQLInputObjectType({
|
||||
name: 'IntFilter',
|
||||
fields: {
|
||||
eq: { type: GraphQLInt },
|
||||
gt: { type: GraphQLInt },
|
||||
gte: { type: GraphQLInt },
|
||||
in: { type: new GraphQLList(new GraphQLNonNull(GraphQLInt)) },
|
||||
lt: { type: GraphQLInt },
|
||||
lte: { type: GraphQLInt },
|
||||
neq: { type: GraphQLInt },
|
||||
is: { type: FilterIsEnumType },
|
||||
},
|
||||
});
|
||||
@ -0,0 +1,12 @@
|
||||
import { GraphQLInputObjectType } from 'graphql';
|
||||
|
||||
import { StringFilterType } from 'src/tenant/schema-builder/graphql-types/input/string-filter.type';
|
||||
import { IntFilter } from 'src/tenant/schema-builder/graphql-types/input/int-filter.type';
|
||||
|
||||
export const MoneyFilterType = new GraphQLInputObjectType({
|
||||
name: 'MoneyFilter',
|
||||
fields: {
|
||||
amount: { type: IntFilter },
|
||||
currency: { type: StringFilterType },
|
||||
},
|
||||
});
|
||||
@ -0,0 +1,27 @@
|
||||
import {
|
||||
GraphQLInputObjectType,
|
||||
GraphQLList,
|
||||
GraphQLNonNull,
|
||||
GraphQLString,
|
||||
} from 'graphql';
|
||||
|
||||
import { FilterIsEnumType } from './filter-is-enum-filter.type';
|
||||
|
||||
export const StringFilterType = new GraphQLInputObjectType({
|
||||
name: 'StringFilter',
|
||||
fields: {
|
||||
eq: { type: GraphQLString },
|
||||
gt: { type: GraphQLString },
|
||||
gte: { type: GraphQLString },
|
||||
in: { type: new GraphQLList(new GraphQLNonNull(GraphQLString)) },
|
||||
lt: { type: GraphQLString },
|
||||
lte: { type: GraphQLString },
|
||||
neq: { type: GraphQLString },
|
||||
is: { type: FilterIsEnumType },
|
||||
startsWith: { type: GraphQLString },
|
||||
like: { type: GraphQLString },
|
||||
ilike: { type: GraphQLString },
|
||||
regex: { type: GraphQLString },
|
||||
iregex: { type: GraphQLString },
|
||||
},
|
||||
});
|
||||
@ -0,0 +1,19 @@
|
||||
import { GraphQLInputObjectType, GraphQLList, GraphQLNonNull } from 'graphql';
|
||||
|
||||
import { TimeScalarType } from 'src/tenant/schema-builder/graphql-types/scalars/time.scalar';
|
||||
|
||||
import { FilterIsEnumType } from './filter-is-enum-filter.type';
|
||||
|
||||
export const TimeFilter = new GraphQLInputObjectType({
|
||||
name: 'TimeFilter',
|
||||
fields: {
|
||||
eq: { type: TimeScalarType },
|
||||
gt: { type: TimeScalarType },
|
||||
gte: { type: TimeScalarType },
|
||||
in: { type: new GraphQLList(new GraphQLNonNull(TimeScalarType)) },
|
||||
lt: { type: TimeScalarType },
|
||||
lte: { type: TimeScalarType },
|
||||
neq: { type: TimeScalarType },
|
||||
is: { type: FilterIsEnumType },
|
||||
},
|
||||
});
|
||||
@ -0,0 +1,11 @@
|
||||
import { GraphQLInputObjectType } from 'graphql';
|
||||
|
||||
import { StringFilterType } from 'src/tenant/schema-builder/graphql-types/input/string-filter.type';
|
||||
|
||||
export const UrlFilterType = new GraphQLInputObjectType({
|
||||
name: 'UrlFilter',
|
||||
fields: {
|
||||
text: { type: StringFilterType },
|
||||
link: { type: StringFilterType },
|
||||
},
|
||||
});
|
||||
@ -0,0 +1,15 @@
|
||||
import { GraphQLInputObjectType, GraphQLList } from 'graphql';
|
||||
|
||||
import { UUIDScalarType } from 'src/tenant/schema-builder/graphql-types/scalars/uuid.scalar';
|
||||
|
||||
import { FilterIsEnumType } from './filter-is-enum-filter.type';
|
||||
|
||||
export const UUIDFilterType = new GraphQLInputObjectType({
|
||||
name: 'UUIDFilter',
|
||||
fields: {
|
||||
eq: { type: UUIDScalarType },
|
||||
in: { type: new GraphQLList(UUIDScalarType) },
|
||||
neq: { type: UUIDScalarType },
|
||||
is: { type: FilterIsEnumType },
|
||||
},
|
||||
});
|
||||
@ -0,0 +1,21 @@
|
||||
import { GraphQLScalarType } from 'graphql';
|
||||
import { Kind } from 'graphql/language';
|
||||
|
||||
export const BigFloatScalarType = new GraphQLScalarType({
|
||||
name: 'BigFloat',
|
||||
description:
|
||||
'A custom scalar type for representing big floating point numbers',
|
||||
serialize(value: number): string {
|
||||
return String(value);
|
||||
},
|
||||
parseValue(value: string): number {
|
||||
return parseFloat(value);
|
||||
},
|
||||
parseLiteral(ast): number | null {
|
||||
if (ast.kind === Kind.FLOAT) {
|
||||
return parseFloat(ast.value);
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
});
|
||||
@ -0,0 +1,20 @@
|
||||
import { GraphQLScalarType } from 'graphql';
|
||||
|
||||
export const BigIntScalarType = new GraphQLScalarType({
|
||||
name: 'BigInt',
|
||||
description:
|
||||
'The `BigInt` scalar type represents non-fractional signed whole numeric values.',
|
||||
serialize(value: bigint): string {
|
||||
return value.toString();
|
||||
},
|
||||
parseValue(value: string): bigint {
|
||||
return BigInt(value);
|
||||
},
|
||||
parseLiteral(ast): bigint | null {
|
||||
if (ast.kind === 'IntValue') {
|
||||
return BigInt(ast.value);
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
});
|
||||
@ -0,0 +1,20 @@
|
||||
import { GraphQLScalarType } from 'graphql';
|
||||
import { Kind } from 'graphql/language';
|
||||
|
||||
export const DateScalarType = new GraphQLScalarType({
|
||||
name: 'Date',
|
||||
description: 'Date custom scalar type',
|
||||
serialize(value: Date): number {
|
||||
return value.getTime();
|
||||
},
|
||||
parseValue(value: number): Date {
|
||||
return new Date(value);
|
||||
},
|
||||
parseLiteral(ast): Date | null {
|
||||
if (ast.kind === Kind.INT) {
|
||||
return new Date(parseInt(ast.value, 10));
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
});
|
||||
@ -0,0 +1,38 @@
|
||||
import { GraphQLScalarType } from 'graphql';
|
||||
import { Kind } from 'graphql/language';
|
||||
|
||||
export const DatetimeScalarType = new GraphQLScalarType({
|
||||
name: 'Datetime',
|
||||
description: 'A custom scalar that represents a datetime in ISO format',
|
||||
serialize(value: string): string {
|
||||
const date = new Date(value);
|
||||
|
||||
if (isNaN(date.getTime())) {
|
||||
throw new Error('Invalid date format, expected ISO date string');
|
||||
}
|
||||
|
||||
return date.toISOString();
|
||||
},
|
||||
parseValue(value: string): Date {
|
||||
const date = new Date(value);
|
||||
|
||||
if (isNaN(date.getTime())) {
|
||||
throw new Error('Invalid date format, expected ISO date string');
|
||||
}
|
||||
|
||||
return date;
|
||||
},
|
||||
parseLiteral(ast): Date {
|
||||
if (ast.kind !== Kind.STRING) {
|
||||
throw new Error('Invalid date format, expected ISO date string');
|
||||
}
|
||||
|
||||
const date = new Date(ast.value);
|
||||
|
||||
if (isNaN(date.getTime())) {
|
||||
throw new Error('Invalid date format, expected ISO date string');
|
||||
}
|
||||
|
||||
return date;
|
||||
},
|
||||
});
|
||||
@ -0,0 +1,24 @@
|
||||
import { GraphQLScalarType } from 'graphql';
|
||||
import { IntValueNode, Kind } from 'graphql/language';
|
||||
|
||||
export const TimeScalarType = new GraphQLScalarType({
|
||||
name: 'Time',
|
||||
description: 'Time custom scalar type',
|
||||
serialize(value: Date): number {
|
||||
return value.getTime();
|
||||
},
|
||||
parseValue(value: number): Date {
|
||||
return new Date(value);
|
||||
},
|
||||
parseLiteral(ast): Date {
|
||||
if (ast.kind === Kind.INT) {
|
||||
const intAst = ast as IntValueNode;
|
||||
|
||||
if (typeof intAst.value === 'number') {
|
||||
return new Date(intAst.value);
|
||||
}
|
||||
throw new Error(`Invalid timestamp value: ${ast.value}`);
|
||||
}
|
||||
throw new Error(`Invalid AST kind: ${ast.kind}`);
|
||||
},
|
||||
});
|
||||
@ -0,0 +1,27 @@
|
||||
import { GraphQLScalarType, Kind } from 'graphql';
|
||||
|
||||
export const UUIDScalarType = new GraphQLScalarType({
|
||||
name: 'UUID',
|
||||
description: 'A UUID scalar type',
|
||||
serialize(value: string): string {
|
||||
if (typeof value !== 'string') {
|
||||
throw new Error('UUID must be a string');
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
parseValue(value: string): string {
|
||||
if (typeof value !== 'string') {
|
||||
throw new Error('UUID must be a string');
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
parseLiteral(ast): string {
|
||||
if (ast.kind !== Kind.STRING) {
|
||||
throw new Error('UUID must be a string');
|
||||
}
|
||||
|
||||
return ast.value;
|
||||
},
|
||||
});
|
||||
@ -5,7 +5,7 @@ import {
|
||||
GraphQLString,
|
||||
} from 'graphql';
|
||||
|
||||
import { PageInfoType } from 'src/tenant/schema-builder/utils/page-into-type.util';
|
||||
import { PageInfoType } from 'src/tenant/schema-builder/graphql-types/object/page-into.type';
|
||||
import { generateConnectionType } from 'src/tenant/schema-builder/utils/generate-connection-type.util';
|
||||
|
||||
describe('generateConnectionType', () => {
|
||||
|
||||
@ -0,0 +1,47 @@
|
||||
import { GraphQLBoolean } from 'graphql';
|
||||
|
||||
import { mapColumnTypeToFilterType } from 'src/tenant/schema-builder/utils/map-column-type-to-filter-type.util'; // Update with the actual path
|
||||
import { FieldMetadata } from 'src/metadata/field-metadata/field-metadata.entity';
|
||||
import { UUIDFilterType } from 'src/tenant/schema-builder/graphql-types/input/uuid-filter.type';
|
||||
import { StringFilterType } from 'src/tenant/schema-builder/graphql-types/input/string-filter.type';
|
||||
import { DateFilterType } from 'src/tenant/schema-builder/graphql-types/input/date-filter.type';
|
||||
import { IntFilter } from 'src/tenant/schema-builder/graphql-types/input/int-filter.type';
|
||||
import { UrlFilterType } from 'src/tenant/schema-builder/graphql-types/input/url-filter.type';
|
||||
import { MoneyFilterType } from 'src/tenant/schema-builder/graphql-types/input/money-filter.type';
|
||||
|
||||
describe('mapColumnTypeToFilterType', () => {
|
||||
it('should map column types to corresponding filter types', () => {
|
||||
const fields: { column: FieldMetadata; expected: any }[] = [
|
||||
{ column: { type: 'uuid' } as FieldMetadata, expected: UUIDFilterType },
|
||||
{ column: { type: 'text' } as FieldMetadata, expected: StringFilterType },
|
||||
{
|
||||
column: { type: 'phone' } as FieldMetadata,
|
||||
expected: StringFilterType,
|
||||
},
|
||||
{
|
||||
column: { type: 'email' } as FieldMetadata,
|
||||
expected: StringFilterType,
|
||||
},
|
||||
{ column: { type: 'date' } as FieldMetadata, expected: DateFilterType },
|
||||
{
|
||||
column: { type: 'boolean' } as FieldMetadata,
|
||||
expected: GraphQLBoolean,
|
||||
},
|
||||
{ column: { type: 'number' } as FieldMetadata, expected: IntFilter },
|
||||
{ column: { type: 'url' } as FieldMetadata, expected: UrlFilterType },
|
||||
{ column: { type: 'money' } as FieldMetadata, expected: MoneyFilterType },
|
||||
];
|
||||
|
||||
fields.forEach((field) => {
|
||||
expect(mapColumnTypeToFilterType(field.column)).toBe(field.expected);
|
||||
});
|
||||
});
|
||||
|
||||
it('should throw an error for unimplemented filter types', () => {
|
||||
const column = { type: 'enum' } as FieldMetadata;
|
||||
|
||||
expect(() => mapColumnTypeToFilterType(column)).toThrowError(
|
||||
'enum filter type not yet implemented',
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -1,6 +1,6 @@
|
||||
import { GraphQLList, GraphQLNonNull, GraphQLObjectType } from 'graphql';
|
||||
|
||||
import { PageInfoType } from './page-into-type.util';
|
||||
import { PageInfoType } from 'src/tenant/schema-builder/graphql-types/object/page-into.type';
|
||||
|
||||
/**
|
||||
* Generate a GraphQL connection type based on the EdgeType.
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
import { GraphQLBoolean } from 'graphql';
|
||||
|
||||
import { FieldMetadata } from 'src/metadata/field-metadata/field-metadata.entity';
|
||||
import { UUIDFilterType } from 'src/tenant/schema-builder/graphql-types/input/uuid-filter.type';
|
||||
import { StringFilterType } from 'src/tenant/schema-builder/graphql-types/input/string-filter.type';
|
||||
import { DateFilterType } from 'src/tenant/schema-builder/graphql-types/input/date-filter.type';
|
||||
import { IntFilter } from 'src/tenant/schema-builder/graphql-types/input/int-filter.type';
|
||||
import { UrlFilterType } from 'src/tenant/schema-builder/graphql-types/input/url-filter.type';
|
||||
import { MoneyFilterType } from 'src/tenant/schema-builder/graphql-types/input/money-filter.type';
|
||||
|
||||
/**
|
||||
* Map the column type from field-metadata to its corresponding filter type.
|
||||
* @param columnType Type of the column in the database.
|
||||
*/
|
||||
export const mapColumnTypeToFilterType = (column: FieldMetadata) => {
|
||||
switch (column.type) {
|
||||
case 'uuid':
|
||||
return UUIDFilterType;
|
||||
case 'text':
|
||||
case 'phone':
|
||||
case 'email':
|
||||
return StringFilterType;
|
||||
case 'date':
|
||||
return DateFilterType;
|
||||
case 'boolean':
|
||||
return GraphQLBoolean;
|
||||
case 'number':
|
||||
return IntFilter;
|
||||
case 'url': {
|
||||
return UrlFilterType;
|
||||
}
|
||||
case 'money': {
|
||||
return MoneyFilterType;
|
||||
}
|
||||
case 'enum':
|
||||
default:
|
||||
throw new Error(`${column.type} filter type not yet implemented`);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user