Created
September 21, 2017 00:58
-
-
Save pencilcheck/cb71850937c0341a9b06a7f8fdee14fd to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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