module.exports = function PgConnectionArgFilter( | |
builder, | |
{ pgInflection: inflection } | |
) { | |
builder.hook( | |
"init", | |
( | |
_, | |
{ | |
addType, | |
getTypeByName, | |
newWithHooks, | |
pgIntrospectionResultsByKind: introspectionResultsByKind, | |
pgGqlInputTypeByTypeId: gqlTypeByTypeId, | |
graphql: { GraphQLInputObjectType, GraphQLBoolean, GraphQLInt, GraphQLString, GraphQLNonNull, GraphQLList }, | |
} | |
) => { | |
const makeFilterFields = (gqlType) => { | |
return { | |
null: { | |
description: "If set to true, checks for null values. If set to false, checks for non-null values.", | |
type: GraphQLBoolean, | |
}, | |
equalTo: { | |
description: "Checks for values equal to this value.", | |
type: gqlType, | |
}, | |
notEqualTo: { | |
description: "Checks for values not equal to this value.", | |
type: gqlType, | |
}, | |
lessThan: { | |
description: "Checks for values less than this value.", | |
type: gqlType, | |
}, | |
lessThanOrEqualTo: { | |
description: "Checks for values less than or equal to this value.", | |
type: gqlType, | |
}, | |
greaterThan: { | |
description: "Checks for values greater than this value.", | |
type: gqlType, | |
}, | |
greaterThanOrEqualTo: { | |
description: "Checks for values greater than or equal to this value.", | |
type: gqlType, | |
}, | |
in: { | |
description: "Checks for values that are in this list.", | |
type: new GraphQLList(new GraphQLNonNull(gqlType)), | |
}, | |
notIn: { | |
description: "Checks for values that are not in this list.", | |
type: new GraphQLList(new GraphQLNonNull(gqlType)), | |
}, | |
}; | |
}; | |
const StringFilter = new GraphQLInputObjectType({ | |
name: "StringFilter", | |
description: `A filter to be used against String fields. All fields are combined with a logical ‘and.’`, | |
fields: makeFilterFields(GraphQLString), | |
}); | |
addType(StringFilter); | |
const IntFilter = new GraphQLInputObjectType({ | |
name: "IntFilter", | |
description: `A filter to be used against Int fields. All fields are combined with a logical ‘and.’`, | |
fields: makeFilterFields(GraphQLInt), | |
}); | |
addType(IntFilter); | |
const DatetimeFilter = new GraphQLInputObjectType({ | |
name: "DatetimeFilter", | |
description: `A filter to be used against Datetime fields. All fields are combined with a logical ‘and.’`, | |
fields: makeFilterFields(getTypeByName("Datetime")), | |
}); | |
addType(DatetimeFilter); | |
const DateFilter = new GraphQLInputObjectType({ | |
name: "DateFilter", | |
description: `A filter to be used against Date fields. All fields are combined with a logical ‘and.’`, | |
fields: makeFilterFields(getTypeByName("Date")), | |
}); | |
addType(DateFilter); | |
const JSONFilter = new GraphQLInputObjectType({ | |
name: "JSONFilter", | |
description: `A filter to be used against JSON fields. All fields are combined with a logical ‘and.’`, | |
fields: { | |
null: { | |
description: "If set to true, checks for null values. If set to false, checks for non-null values.", | |
type: GraphQLBoolean, | |
} | |
} | |
}); | |
addType(JSONFilter); | |
introspectionResultsByKind.class.map(table => { | |
const tableTypeName = inflection.tableType( | |
table.name, | |
table.namespace && table.namespace.name | |
); | |
newWithHooks( | |
GraphQLInputObjectType, | |
{ | |
description: `A filter to be used against \`${tableTypeName}\` object types. All fields are combined with a logical ‘and.’`, | |
name: `${inflection.tableType( | |
table.name, | |
table.namespace && table.namespace.name | |
)}Filter`, | |
fields: ({ fieldWithHooks }) => | |
introspectionResultsByKind.attribute | |
.filter(attr => attr.classId === table.id) | |
.reduce((memo, attr) => { | |
const fieldName = inflection.column( | |
attr.name, | |
table.name, | |
table.namespace && table.namespace.name | |
); | |
const fieldFilterTypeByFieldTypeName = { | |
String: StringFilter, | |
Int: IntFilter, | |
Datetime: DatetimeFilter, | |
Date: DateFilter, | |
JSON: JSONFilter | |
} | |
const fieldType = gqlTypeByTypeId[attr.typeId]; | |
const fieldFilterType = fieldFilterTypeByFieldTypeName[fieldType.name]; | |
if (fieldFilterType != null) { | |
memo[fieldName] = fieldWithHooks( | |
fieldName, | |
{ | |
description: `Filter by the object’s \`${fieldName}\` field.`, | |
type: fieldFilterType, | |
}, | |
{ | |
isPgConnectionFilterInputField: true, | |
} | |
); | |
} | |
return memo; | |
}, {}), | |
}, | |
{ | |
pgIntrospection: table, | |
isPgFilter: true, | |
} | |
); | |
}); | |
return _; | |
} | |
); | |
builder.hook( | |
"GraphQLObjectType:fields:field:args", | |
( | |
args, | |
{ | |
pgSql: sql, | |
gql2pg, | |
extend, | |
getTypeByName, | |
pgIntrospectionResultsByKind: introspectionResultsByKind, | |
}, | |
{ | |
scope: { isPgConnectionField, pgIntrospection: table }, | |
addArgDataGenerator, | |
} | |
) => { | |
if (!isPgConnectionField || !table || table.kind !== "class") { | |
return args; | |
} | |
const TableFilterType = getTypeByName( | |
`${inflection.tableType( | |
table.name, | |
table.namespace && table.namespace.name | |
)}Filter` | |
); | |
addArgDataGenerator(function connectionFilter({ filter }) { | |
return { | |
pgQuery: queryBuilder => { | |
if (filter != null) { | |
introspectionResultsByKind.attribute | |
.filter(attr => attr.classId === table.id) | |
.forEach(attr => { | |
const fieldName = inflection.column( | |
attr.name, | |
table.name, | |
table.namespace.name | |
); | |
const fieldFilter = filter[fieldName]; | |
if (fieldFilter != null) { | |
Object.keys(fieldFilter).forEach(operator => { | |
const sqlField = sql.fragment`${queryBuilder.getTableAlias()}.${sql.identifier(attr.name)}`; | |
if (operator === "null") { | |
queryBuilder.where( | |
sql.fragment`${sqlField} ${fieldFilter[operator] | |
? sql.fragment`IS NULL` | |
: sql.fragment`IS NOT NULL`}` | |
); | |
} else if (operator === "equalTo") { | |
queryBuilder.where( | |
sql.fragment`${sqlField} = ${gql2pg(fieldFilter[operator], attr.type)}` | |
); | |
} else if (operator === "notEqualTo") { | |
queryBuilder.where( | |
sql.fragment`${sqlField} <> ${gql2pg(fieldFilter[operator], attr.type)}` | |
); | |
} else if (operator === "lessThan") { | |
queryBuilder.where( | |
sql.fragment`${sqlField} < ${gql2pg(fieldFilter[operator], attr.type)}` | |
); | |
} else if (operator === "lessThanOrEqualTo") { | |
queryBuilder.where( | |
sql.fragment`${sqlField} <= ${gql2pg(fieldFilter[operator], attr.type)}` | |
); | |
} else if (operator === "greaterThan") { | |
queryBuilder.where( | |
sql.fragment`${sqlField} > ${gql2pg(fieldFilter[operator], attr.type)}` | |
); | |
} else if (operator === "greaterThanOrEqualTo") { | |
queryBuilder.where( | |
sql.fragment`${sqlField} >= ${gql2pg(fieldFilter[operator], attr.type)}` | |
); | |
} else if (operator === "in") { | |
const list = sql.join( | |
fieldFilter[operator].map(val => gql2pg(val, attr.type)), | |
", " | |
); | |
queryBuilder.where( | |
sql.fragment`${sqlField} IN (${list})` | |
); | |
} else if (operator === "notIn") { | |
const list = sql.join( | |
fieldFilter[operator].map(val => gql2pg(val, attr.type)), | |
", " | |
); | |
queryBuilder.where( | |
sql.fragment`${sqlField} NOT IN (${list})` | |
); | |
} | |
}); | |
} | |
}); | |
} | |
}, | |
}; | |
}); | |
return extend(args, { | |
filter: { | |
description: | |
"A filter to be used in determining which values should be returned by the collection.", | |
type: TableFilterType, | |
}, | |
}); | |
} | |
); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment