npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

typeorm-filter

v0.0.7

Published

typeorm-filter provides a more complex API for filter

Downloads

26

Readme

typeorm-filter

The typeorm-filter provides

Install

With npm

npm install typeorm-filter

With yarn

yarn add typeorm-filter

How to use

import { filter } from "src/helpers/typeorm-filter";

const userRepository = getRepository(User);
const users = filter(userRepository, {
  filters: [
    {
      email: {
        starts_with: "admin",
        ends_with: "@gmail.com",
      },
    },
  ],
});

The previous filter will map to the following SQL condition:

WHERE (email ILIKE 'admin%' AND email ILIKE '%gmail.com')

You can do as many combinations as you like.

Methods

filter<T>(repository, query, configuration)

filter(repository, {
	page: 1,
	limit: undefined,
	filters: [],
	relations: [],
	order: [],
	select: [],
	search: {
		term: undefined,
		fields: []
	},
}, {
	filterableColumns: [],
	sortableColumns: [],
	searchableColumns: [],
	customFilter: {},
	modify: (queryBuilder, tableAlias?:  string) =>  void,
	paginate: true,
	ignoreException: true
})
query.page

The current page

query.limit

The limit per page

query.filters

More details here

query.relations

Array containing all the relations to be joined on the main table

query.order

Array containing all the fields to be ordered. Possible values are: field or field:asc or field:desc.
For example: ['firstName: desc', 'lastName:asc', 'createdAt']

query.select

Array containing all the fields that will be added to the response

query.search.term

String to filter the query.search.fields

query.search.fields

Array containing all the columns that will be filtered with the query.search.term

configuration.filterableColumns

Array containing all the columns that can be filtered. When empty, all the columns can be filtered.

configuration.sortableColumns

Array containing all the columns that can be sorted. When empty, all the columns can be sorted.

configuration.searchableColumns

Array containing all the columns that can be searched with the query.search.term. When empty, all the columns can be sorted.

configuration.customFilter

Object containing all custom filters. When this field is found inside the query.filters the custom filter specified here will be applied. See more here.

configuration.modify

Function where you can access the query builder for the specified repository.

configuration.paginate

Boolean value that defines if the query has to be paginated. Default is true.

configuration.ignoreException

Boolean value that defines if the exception (when exists) has to be ignored. For example, if the specified field do not exists, that will throw an exception in the database. Default is true.

Complete example

// user.model.ts
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  firstName: string;

  @Column()
  lastName: string;

  @Column()
  isAdmin: boolean;

  @Column()
  createdAt: Date;
}
// profile.model.ts
export class Profile {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;
}
// user-profile.model.ts
export class UserProfile {
  @Column()
  userId: number;

  @Column()
  profileId: number;

  @ManyToOne(() => User)
  user: User;

  @ManyToOne(() => Profile)
  profile: Profile;
}
const userRepository = getRepository(User);

const users = filter<User>(
  repository,
  {
    page: 1,
    limit: 10,
    filters: [{ firstName: { contains: "jo", not: { eq: "John" } } }, { lastName: { not: { eq: "Doe" } } }],
    relations: ["profiles"],
    order: ["firstName:asc", "lastName:desc", "createdAt"],
    select: ["id", "firstName", "profiles.name"],
    search: {
      term: "john",
      fields: ["firstName"],
    },
  },
  {
    filterableColumns: ["firstName", "lastName", "isAdmin"],
    sortableColumns: ["firstName", "lastName", "createdAt"],
    searchableColumns: ["firstName", "lastName"],
    customFilter: {
      hasProfile: (queryBuilder, filterValue, mainTableAlias) => {
        queryBuilder.where(`${mainTableAlias}.profiles IS NOT NULL`);
      },
    },
    modify: (queryBuilder, mainTableAlias) => {
      queryBuilder.where(`(${mainTableAlias}.firstName || ${mainTableAlias}.lastName) IS NOT NULL`);
    },
    paginate: true,
    ignoreException: true,
  }
);

console.log(users);
// {
//   data: [],
//   meta: { pagination: { page: 1, perPage: 10, total: 100, pages: 10 } }
// }

query.search and query.filters

If you use both filters, they will be joined with logical operator AND. For example:

filter(userRepository, {
  search: {
    term: "john",
    fields: ["firstName", "lastName"],
  },
  filters: [{ email: { eq: "[email protected]" } }, { createdAt: { gte: "2022-08-01" } }],
});

That will be mapped to the following SQL condition:

WHERE
-- query.s
(firstName ILIKE '%john%' OR lastName ILIKE '%john%')

AND -- LOGICAL OPERATOR JOIN query.s WITH query.filter

-- query.filter
((email = '[email protected]') AND (createdAt >= '2022-08-01'))

Filter response

The filter function will return the results with the following structure:

{
  "data": [
    {
      "firstName": "John",
      "lastName": "Doe",
      "createdAt": "2022-07-02 13:32:12"
    },
    {
      "firstName": "Mike",
      "lastName": "Tyson",
      "createdAt": "2022-02-01 11:32:12"
    }
  ],
  "meta": {
    "error": null,
    "pagination": {
      "page": 1,
      "perPage": 2,
      "pages": 50,
      "total": 100
    }
  }
}

If something goes wrong with the query, the meta.error property will contain an string with the error message.

Conditional operators

eq

Example:

filter(userRepository, {
  filters: [{ email: { eq: "[email protected]" } }],
});

That will be mapped to the following SQL condition:

WHERE email = '[email protected]'

contains

Example:

filter(userRepository, {
  filters: [{ email: { contains: "admin" } }],
});

That will be mapped to the following SQL condition:

WHERE email ILIKE '%admin%'

in

Example:

filter(userRepository, {
  filters: [{ email: { in: ["[email protected]", "[email protected]"] } }],
});

That will be mapped to the following SQL condition:

WHERE email IN ('[email protected]', '[email protected]')

gt

Example:

filter(userRepository, {
  filters: [{ created_at: { gt: "2019-08-01" } }],
});

That will be mapped to the following SQL condition:

WHERE created_at > '2019-08-01'

gte

Example:

filter(userRepository, {
  filters: [{ created_at: { gte: "2019-08-01" } }],
});

That will be mapped to the following SQL condition:

WHERE created_at >= '2019-08-01'

lt

Example:

filter(userRepository, {
  filters: [{ created_at: { lt: "2018-08-01" } }],
});

That will be mapped to the following SQL condition:

WHERE created_at < '2018-08-01'

lte

Example:

filter(userRepository, {
  filters: [{ created_at: { lte: "2018-08-01" } }],
});

That will be mapped to the following SQL condition:

WHERE created_at <= '2018-08-01'

between

Example:

filter(userRepository, {
  filters: [{ created_at: { between: ["2018-08-01", "2019-08-01"] } }],
});

That will be mapped to the following SQL condition:

WHERE created_at BETWEEN '2018-08-01' AND '2019-08-01'

not

Example:

filter(userRepository, {
  filters: [{ email: { not: { eq: "[email protected]" } } }],
});

That will be mapped to the following SQL condition:

WHERE email != '[email protected]'

is_null

Example:

filter(userRepository, {
  filters: [{ email: { is_null: true } }, { first_name: { is_null: false } }],
});

That will be mapped to the following SQL condition:

WHERE email IS NULL AND first_name IS NOT NULL

starts_with

Example:

filter(userRepository, {
  filters: [{ email: { starts_with: "admin" } }],
});

That will be mapped to the following SQL condition:

WHERE email ILIKE 'admin%'

ends_with

Example:

filter(userRepository, {
  filters: [{ email: { ends_with: "@gmail.com" } }],
});

That will be mapped to the following SQL condition:

WHERE email ILIKE '%@gmail.com'

Logical operators

OR

Example:

filter(userRepository, {
  filters: [
    {
      OR: [{ email: { eq: "[email protected]" } }, { is_admin: { is_true: true } }],
    },
  ],
});

That will be mapped to the following SQL condition:

WHERE (email = '[email protected]') OR (is_admin IS TRUE)

Single field

When inside a field, you can use OR as an object to apply multiple conditions to the same field.

filter(userRepository, {
  filters: [
    {
      email: {
        OR: {
          starts_with: "admin",
          ends_with: "@gmail.com",
        },
      },
    },
  ],
});

That will be mapped to the following SQL condition:

WHERE (email ILIKE 'admin%' OR email ILIKE '%@gmail.com')

AND

Example:

filter(userRepository, {
  filters: [
    {
      AND: [{ email: { eq: "[email protected]" } }, { created_at: { gte: "2022-08-01" } }],
    },
  ],
});

That will be mapped to the following SQL condition:

WHERE (email ILIKE '%@gmail.com') AND (email >= '2022-08-01')

Note: The AND is used by default when there is multiple conditions, the example is just to illustrate how to use if needed. In other words, this is the same:

filter(userRepository, {
  filters: [{ email: { eq: "[email protected]" } }, { created_at: { gte: "2022-08-01" } }],
});

The use case for the AND is most suitable for a more advanced usage

Custom filters

You can define custom filters that will be applied when found in query.filters.

filter(userRepository, {
  filters: [
    { isRegisterComplete: true },
  ]
}, {
	customFilter: {
      isRegisterComplete(queryBuilder: WhereExpressionBuilder, filterValue?: any, alias?: string) => {
	    if (filterValue === true) {
          queryBuilder.where("email IS NOT NULL AND last_name IS NOT NULL");
        }
      }
    }
})

You can also combine with any other filters.

Advances usage

Multiple filters

You can apply as many filters as you want:

filter(userRepository, [
	filters: [
		{ first_name: { not: { eq: 'John' } } },
		{ first_name: { contains: 'ke' } },
		{ last_name: { not: { eq: 'Doe' } } }
	]
])

That will be mapped to the following SQL condition:

WHERE
	(first_name != 'John')
	AND (first_name ILIKE '%ke%')
	AND (last_name != 'Doe')

Multiple conditions on same field

If you want to apply multiple conditions to the same field, just added more the others conditions on the field object.

filter(userRepository, {
  filters: [
    {
      first_name: {
        not: { eq: "John" },
        contains: "ke",
      },
    },
  ],
});

That will be mapped to the following SQL condition:

WHERE (first_name != 'John' AND first_name ILIKE '%ke%')

Nested logical operators

You can nested logical operators as many as you want. Each nested object or array will encapsulated in a new group.

await filter(pessoaRepository, {
  filters: [
    {
      OR: [
        {
          OR: [],
          field: {
            OR: { OR: { OR: {} } },
          },
        },
      ],
    },
  ],
});

Grouping conditions

Each array and element of the filter creates a new group.

await filter(pessoaRepository, {
    filters: [
      {
        AND: [
          {
            OR: [
              {
                first_name: { starts_with: "di" },
                last_name: { ends_with: "go" },
                age: { OR: { gte: 18, lte: 60 } },
              },
              {
                OR: [{ profile: { eq: "admin" } }, { profile: { eq: "manager" } }],
                is_public_access: { is_true: true },
              },
              {
                profile: { eq: "not required" },
              },
            ],
          },
          {
            status: { eq: "online" },
          },
        ],
        OR: [
          {
            priority: { eq: 1, OR: { lte: 1, gte: 3 } },
          },
          {
            priority: { eq: 2 },
          },
        ],
      },
      {
        first_name: {
          not: {
         eq: "teste",
            OR: {
              starts_with: "p",
              ends_with: "g",
          },
          OR: {
            starts_with: "di",
            ends_with: "go",
            not: {
              eq: "teste",
              OR: {
                starts_with: "10",
                ends_with: "11",
              },
            },
          },
        },
      },
    ],
  }
)

That will be mapped to the following SQL condition:

WHERE
    (
        (
            (
                (
                    (
                        (
                            first_name ILIKE 'di%'
                            AND last_name ILIKE '%go'
                            AND (
                                age >= 18
                                OR age <= 60
                            )
                        )
                        OR (
                            (
                                (profile = 'admin')
                                OR (profile = 'manager')
                            )
                            AND (is_public_access IS TRUE)
                        )
                        OR (profile = 'not required')
                    )
                )
                AND (CAST(status AS TEXT) = $ 9)
            )
            AND (
                (
                    priority = 1
                    AND (
                        priority <= 1
                        OR priority >= 3
                    )
                )
                OR (priority = 2)
            )
        )
        AND (
            (
                first_name != 'teste'
                AND (
                    first_name NOT ILIKE 'p%'
                    OR first_name NOT ILIKE '%g')
                )
            )
            AND (
                first_name ILIKE 'di%'
                OR first_name ILIKE 'go%'
                AND (
                    first_name != 'teste')
                    AND (
                        first_name NOT ILIKE '10%'
                        OR first_name NOT ILIKE '%11'
                    )
                )
            )
        )
    )

Using with query string

The typeorm-filter helps you to create the filter from a query string, for that just build the query string according to the filter array from the filter function options.

Example 1:

?page=1
&limit=50
&select[]=firstName
&select[]=lastName
&select[]=profile.name
&order[]=firstName:desc
&relations[]=profile
&filters[0][email][starts_with]=admin
&filters[0][email][ends_with][email protected]
&filters[1][created_at][lte]=2020-01-01

Example 2:

?
page=1
&limit=50
&search[term]=john
&search[fields][]=firstName
&search[fields][]=lastName

Most frameworks already converts the query string to the expected. But if this is not your case you can use the createFilterFromQuery function:

import express from "express";
import { createFilterFromQuery } from "typeorm-filter";

const app = express();

app.get("/", function (req, res) {
  const filter = createFilterFromQuery({ query: req.query });

  return filter;
});

!!createFilterFromQuery do not exists yet.

Typed query string [TO DO]

@ParseFilterQuery(): UserFilter
const filter = createFilterFromQuery({ query: req.query, transformerClass: UserFilter });

Decorators [TODO]

NestJS

ParsedFilterQuery<T>

This decorator will automatically create the filter from the incoming query string using the createFilterFromQueryfunction.

@Get()
async index(@ParsedFilterQuery() query: FilterQuery<User>) {
	return query;
}

Why not the Find API?