Skip to content

Instantly share code, notes, and snippets.

@pencilcheck
Created September 21, 2017 00:58
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save pencilcheck/cb71850937c0341a9b06a7f8fdee14fd to your computer and use it in GitHub Desktop.
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