Skip to content

Commit

Permalink
fix: multiple simple string filter override each other
Browse files Browse the repository at this point in the history
We fix this by always creating an AND array, so that two OR's don't override each other
  • Loading branch information
macrozone committed May 20, 2020
1 parent d32bf49 commit 1b7a40f
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 79 deletions.
34 changes: 20 additions & 14 deletions packages/dataprovider/src/buildVariables.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,24 +41,30 @@ describe("buildVariables", () => {

expect(result).toEqual<NexusGenArgTypes["Query"]["users"]>({
where: {
yearOfBirth: {
equals: 1879,
},
OR: [
AND: [
{
firstName: {
contains: "fooBar",
yearOfBirth: {
equals: 1879,
},
},
{
firstName: {
contains: "foobar",
},
},
{
firstName: {
contains: "FooBar",
},
OR: [
{
firstName: {
contains: "fooBar",
},
},
{
firstName: {
contains: "foobar",
},
},
{
firstName: {
contains: "FooBar",
},
},
],
},
],
},
Expand Down
104 changes: 67 additions & 37 deletions packages/dataprovider/src/buildWhere.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,50 @@ describe("buildWhere", () => {
const filter = {
yearOfBirth: 1879,
firstName: "fooBar",
lastName: "einstein",
};
const result = buildWhere(filter, testUserResource, testIntrospection);

expect(result).toEqual<NexusGenArgTypes["Query"]["users"]["where"]>({
yearOfBirth: {
equals: 1879,
},
OR: [
AND: [
{
firstName: {
contains: "fooBar",
yearOfBirth: {
equals: 1879,
},
},
{
firstName: {
contains: "foobar",
},
OR: [
{
firstName: {
contains: "fooBar",
},
},
{
firstName: {
contains: "foobar",
},
},
{
firstName: {
contains: "FooBar",
},
},
],
},
{
firstName: {
contains: "FooBar",
},
OR: [
{
lastName: {
contains: "einstein",
},
},

{
lastName: {
contains: "Einstein",
},
},
],
},
],
});
Expand Down Expand Up @@ -129,46 +151,54 @@ describe("buildWhere", () => {
const result = buildWhere(filter, testUserResource, testIntrospection);

expect(result).toEqual<NexusGenArgTypes["Query"]["users"]["where"]>({
yearOfBirth: {
equals: 1879,
},
roles: {
some: {
id: {
equals: "admin",
AND: [
{
yearOfBirth: {
equals: 1879,
},
},
{
roles: {
some: {
id: {
equals: "admin",
},
},
},
},
},
OR: [
{
OR: [
{
firstName: {
contains: "fooBar",
},
OR: [
{
firstName: {
contains: "fooBar",
},
},
{
firstName: {
contains: "foobar",
},
},
{
firstName: {
contains: "FooBar",
},
},
],
},
{
firstName: {
contains: "foobar",
lastName: {
startsWith: "Ein",
},
},
{
firstName: {
contains: "FooBar",
equals: "Albert",
},
},
],
},
{
lastName: {
startsWith: "Ein",
},
},
{
firstName: {
equals: "Albert",
},
},
],
});
});
Expand Down
79 changes: 51 additions & 28 deletions packages/dataprovider/src/buildWhere.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,48 @@ import upperFirst from "lodash/upperFirst";
import { IntrospectionResult, Resource } from "./constants/interfaces";
import { isObject } from "lodash";

const getStringFilter = (key: string, value: any) => ({
OR: [
const getStringFilter = (key: string, value: any) => {
const OR = [
{
[key]: {
contains: value,
},
},
{
];
const valueLowerCased = value.toLowerCase();
if (valueLowerCased !== value) {
OR.push({
[key]: {
contains: value.toLowerCase(),
contains: valueLowerCased,
},
},
{
});
}
const valueUpperFirst = upperFirst(value);

if (valueUpperFirst !== value) {
OR.push({
[key]: {
contains: upperFirst(value),
contains: valueUpperFirst,
},
},
],
});
});
}
return { OR };
};
const getFilters = (
key: string,
value: any,
whereType: IntrospectionInputObjectType,

introspectionResults: IntrospectionResult,
) => {
if (key === "NOT" || key === "OR" || key === "AND") {
return {
[key]: value.map((f) =>
buildWhereWithType(f, introspectionResults, whereType),
),
};
}

const fieldType = whereType.inputFields.find((f) => f.name === key)
?.type as IntrospectionInputObjectType;

Expand Down Expand Up @@ -122,26 +138,33 @@ const buildWhereWithType = (
introspectionResults: IntrospectionResult,
whereType: IntrospectionInputObjectType,
) => {
const where = Object.keys(filter ?? {}).reduce((acc, key) => {
if (key === "NOT" || key === "OR" || key === "AND") {
return {
...acc,
[key]: filter[key].map((f) =>
buildWhereWithType(f, introspectionResults, whereType),
),
};
}
const where = Object.keys(filter ?? {}).reduce(
(acc, key) => {
// defaults to AND
const filters = getFilters(
key,
filter[key],
whereType,

const filters = getFilters(
key,
filter[key],
whereType,

introspectionResults,
);
introspectionResults,
);

return { ...acc, ...filters };
}, {});
return { ...acc, AND: [...acc.AND, filters] };
},
{ AND: [] },
);
// simplify AND if there is only one
if (where.AND.length === 0) {
delete where.AND;
}
if (where.AND?.length === 1) {
const singleAnd = where.AND[0];
delete where.AND;
return {
...where,
...singleAnd,
};
}
return where;
};
export const buildWhere = (
Expand Down

0 comments on commit 1b7a40f

Please sign in to comment.