GithubHelp home page GithubHelp logo

nestjsx / nestjs-typeorm-paginate Goto Github PK

View Code? Open in Web Editor NEW
815.0 815.0 119.0 2.86 MB

:page_with_curl: Pagination response object function + types for typeorm + nestjs

License: MIT License

TypeScript 98.27% JavaScript 1.73%
nestjs pagination typeorm

nestjs-typeorm-paginate's Introduction

Nestjsx Logo

A set of opinionated NestJS extensions and modules

Travis Coverage Status

Packages

  • @nestjsx/common - A set of NestJs decorators, interfaces and configuration for application modules bootstraping.

Tests

npm run test

nestjs-typeorm-paginate's People

Contributors

akashrrao avatar atixx avatar audibookning avatar bashleigh avatar blazk0 avatar brunokrebs avatar caballerog avatar dependabot-preview[bot] avatar dependabot[bot] avatar duysolo avatar elbarae1921 avatar fabicsp avatar foreshadowru avatar garfield550 avatar jely2002 avatar jesussegado avatar johannesschobel avatar leandro-gomez avatar nick-allen avatar rafamarts avatar rex2002xp avatar rudolfmedula avatar scrip7 avatar sfelix-martins avatar tautvydasderzinskas avatar zier avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nestjs-typeorm-paginate's Issues

Sort in other table by name

I want to sort the photo list by the name of the user which is related by userId. Right now, I could sort in only photo entity area, but sort by userId. How can I do that? Thanks

PhotoEntity = {
 id: string, 
 photoName: string, 
 url: string,
 userId: string
}

UserEntity = {
id: string, 
name: string
}

   const { page = 1, limit = 10 } = filters;
    return paginate<Photo>( this.photoRepository,
      { page, limit },
      { order: { 'user.name': "DESC" }},
    );

Version 1.0.3 issue

Looks like a 1.0.3 version on npmjs.com and yarnpkg.com contains files from the 1.0.1 version.

Behavior of page and next

Thank you for a great library for pagination. However, I think I found some issues.
I am not sure if I understood why page 0 and page 1 are interchangeable.
In paginate.ts

function resolveOptions(options: IPaginationOptions): [number, number, string] {
  const page =
    options.page > 0 ? options.page - 1 : options.page < 0 ? 0 : options.page;
  const limit = options.limit;
  const route = options.route;

  return [page, limit, route];
}

page 1 and page 0 both returns 0. Is that supposed to be correct?
This breaks the behavior of next as well.

function createPaginationObject<T>(
  items: T[],
  total: number,
  page: number,
  limit: number,
  route?: string
) {
  const isNext = route && total / limit >= page + 1;
  const isPrevious = route && page > 0;
  const routes = {
    next: isNext ? `${route}?page=${page + 2}&limit=${limit}` : "",
    previous: isPrevious ? `${route}?page=${page}&limit=${limit}` : ""
  };

  return new Pagination(
    items,
    items.length,
    total,
    Math.ceil(total / limit),
    routes.next,
    routes.previous
  );
}

Let us say we have total 5 elements and limit to be 1.

At page 5, we would expect the next be blank because there is no next element.
However, since page becomes 4 due to resolveOptions this will make next with page=6&limit=1.

error group by when query parameter with if-else statement

I got an error invoice.total must be in the group by clause

invoice.service.ts

findSumPayment(option: PaginationOP) {
    const queryBuilder = this.invoiceRepository
      .createQueryBuilder('invoice')
      .select([
        'invoice.invoice_id AS invoice_id',
        'invoice.total AS total',
        'COAlESCE(SUM(payment.amount),0)::FLOAT AS paid',
        'invoice.total - COAlESCE(SUM(payment.amount),0)::FLOAT AS due',
        'invoice.invoice_date AS invoice_date',
      ])
      .leftJoin('invoice.payment', 'payment')

      .groupBy('invoice.invoice_id')
      .orderBy('invoice.invoice_id', 'DESC');

   #- without if statement paginationRaw work fine if I using if-statement will got an error with paginationRaw
    if (option.enum === '=') {
      queryBuilder.having(
        `invoice.total - COAlESCE(SUM(payment.amount),0)::FLOAT =  0`
      );
    }
    if (option.enum === '>') {
      queryBuilder.having(
        `invoice.total - COAlESCE(SUM(payment.amount),0)::FLOAT >  0`
      );
    }

    #-returnwith paginationRaw **Error GROUP BY invoice.total**
    return from(paginateRaw(queryBuilder, option));

    #-return without paginationRaw **WORK FINE**
    return from(queryBuilder.getRawMany());
  }

Error Message when using return with paginationRaw

column "invoice.total" must appear in the GROUP BY clause or be used in an aggregate function
inside the function above when I use

InvoiceEntity

@Entity({ name: 'invoice' })
export class InvoiceEntity extends ShareEntity {
  @PrimaryGeneratedColumn()
  invoice_id: number;

  @Column({ nullable: true, default: 0 })
  total: number;

  @Column({ type: 'date', default: () => 'NOW()' })
  invoice_date: Date;

  @OneToMany(() => OrderEntity, (entity) => entity.invoice)
  order: OrderEntity;
  @OneToMany(() => PaymentEntity, (entity) => entity.invoice)
  payment: PaymentEntity;

  @ManyToOne(() => CustomerEntity, (entity) => entity.invoice)
  @JoinColumn({ name: 'customer_id', referencedColumnName: 'customer_id' })
  customer: CustomerEntity;
  @Column()
  customer_id: number;

  @OneToOne(() => DeliveryEntity, (entity) => entity.invoice)
  delivery: DeliveryEntity;
}

PaymentEntity

@Entity({ name: 'payments' })
export class PaymentEntity extends ShareEntity {
  @PrimaryGeneratedColumn()
  payment_id: number;

  @Column({ default: 0, nullable: true })
  receive: number;

  @Column()
  amount: number;

  @Column({ type: 'enum', enum: Money, default: Money.USD })
  money: Money;

  @Column({ default: 0, nullable: true })
  payback: number;

  @Column({ type: 'date', default: () => 'NOW()' })
  payment_date: Date;

  @ManyToOne(() => InvoiceEntity, (entity) => entity.payment)
  @JoinColumn({ name: 'invoice_id', referencedColumnName: 'invoice_id' })
  invoice: InvoiceEntity;
  @Column()
  invoice_id: number;
}

os: Mac BigSur
package.json

"dependencies": {
    "@mapbox/node-pre-gyp": "^1.0.1",
    "@nestjs/common": "^7.5.1",
    "@nestjs/config": "^0.6.1",
    "@nestjs/core": "^7.5.1",
    "@nestjs/jwt": "^7.2.0",
    "@nestjs/microservices": "^7.6.5",
    "@nestjs/passport": "^7.1.5",
    "@nestjs/platform-express": "^7.5.1",
    "@nestjs/platform-fastify": "^7.5.5",
    "@nestjs/platform-socket.io": "^7.6.15",
    "@nestjs/terminus": "^7.1.2",
    "@nestjs/typeorm": "^7.1.5",
    "@nestjs/websockets": "^7.6.15",
    "@types/compression": "^1.7.0",
    "@types/passport-jwt": "^3.0.3",
    "argon2": "^0.27.1",
    "cache-manager": "^3.4.0",
    "chalk": "^4.1.0",
    "class-transformer": "^0.4.0",
    "class-validator": "^0.12.2",
    "date-fns": "^2.17.0",
    "dotenv": "^8.2.0",
    "env-cmd": "^10.1.0",
    "fastify-compress": "^3.4.2",
    "fastify-helmet": "^5.3.0",
    "fastify-multer": "^2.0.2",
    "fastify-multipart": "^4.0.3",
    "fastify-static": "^4.0.1",
    "fastify-swagger": "^4.4.1",
    "graphql": "^15.5.0",
    "nestjs-config": "^1.4.7",
    "nestjs-typeorm-paginate": "2.2.6",
    "passport": "^0.4.1",
    "passport-jwt": "^4.0.0",
    "passport-local": "^1.0.0",
    "pg": "^8.5.1",
    "reflect-metadata": "^0.1.13",
    "rimraf": "^3.0.2",
    "rxjs": "^6.6.3",
    "socket.io-redis": "^6.1.0",
    "typeorm": "^0.2.31",
    "webpack": "^4.0.0"
  },
  "devDependencies": {
    "@nestjs/cli": "^7.5.1",
    "@nestjs/schematics": "^7.1.3",
    "@nestjs/swagger": "^4.7.5",
    "@nestjs/testing": "^7.5.1",
    "@types/bcrypt": "^3.0.0",
    "@types/busboy": "^0.2.3",
    "@types/cache-manager": "^2.10.3",
    "@types/express": "^4.17.8",
    "@types/jest": "^26.0.15",
    "@types/node": "^14.14.6",
    "@types/passport-local": "^1.0.33",
    "@types/socket.io": "^2.1.13",
    "@types/supertest": "^2.0.10",
    "@typescript-eslint/eslint-plugin": "^4.6.1",
    "@typescript-eslint/parser": "^4.6.1",
    "eslint": "^7.12.1",
    "eslint-config-prettier": "^6.15.0",
    "eslint-plugin-nestjs": "^1.2.3",
    "eslint-plugin-prettier": "^3.1.4",
    "jest": "^26.6.3",
    "prettier": "^2.1.2",
    "supertest": "^6.0.0",
    "ts-jest": "^26.4.3",
    "ts-loader": "^8.0.8",
    "ts-node": "^9.0.0",
    "tsconfig-paths": "^3.9.0",
    "typescript": "^4.0.5"
  },

error in paginateRaw

const totalQueryBudiler=queryBuilder.clone() and use in Promise.all([queryBuilder.page(page-1).offset(limit),totalQueryBuilder.getCount)] 

so error from totalQueryBuilder.getCount()

Search Options not working

Hi

I'm trying to paginate a list of objects and also use some search options.

return paginate<MyEntity>(this.myEntityRepository, paginationOptions, params)

"params" is:

{ name: FindOperator { _type: 'like', _value: '%test%', _useParameter: true, _multipleParameters: false } }

"paginationOptions" is: { page: '1', limit: '10' }

The problem is that instead of returning only the elements that contain "test" in their name, it returns the whole list.
I also tried with params being {name: "test"}, without the LIKE operator. Same result unfortunately...

Update documentation

Please update documentation for controller

  @Get('')
  async index(
    @Query('page') page: number = 1, 
    @Query('limit') limit: number = 10,
  ): Pagination<CatEntity> {      //The return type of an async function or method must be the global Promise<T> type.
    limit = limit > 100 ? 100 : limit;
    return this.catService.paginate({
      page,
      limit,
      route: 'http://cats.com/cats',
    });
  }

to

Promise<Pagination<CatEntity>>

error has no exported member 'paginate on 2.1.0

found bellow error when update 2.1.0 with no modified
` error TS2305: Module '"../../node_modules/nestjs-typeorm-paginate"' has no exported member 'paginate'.

5 import { paginate, IPaginationOptions} from 'nestjs-typeorm-paginate';
~~~~~~~~
error TS2305: Module '"../../node_modules/nestjs-typeorm-paginate"' has no exported member 'IPaginationOptions'.

5 import { paginate, IPaginationOptions} from 'nestjs-typeorm-paginate';`

Add the ability to use offset and limit instead of take and skip.

Add the ability to use offset and limit instead of take and skip.

Please add the ability to change the selection of skip to offset and take to limit methods to the library.
Reason when there are a large number of records in the table (several million), distinct spoils the query.

Paginate returns empty but query has data

Hello!

I'm trying to get some data from database and pass into paginate as follows:

const user = req.user;

    const walletIds = await Wallet.find({
      select: ['id'],
      where: { userId: user.id },
    });

    const queryBuilder = await getConnection().createQueryBuilder();
    queryBuilder.select(
      'DATE_FORMAT(operations.date, "%Y-%m-%d") as date,' +
        'SUM(operations.numberOfContracts) as numberOfContracts, SUM(operations.value) as value,' +
        '(select name from wallets where wallets.id = operations.walletId) as walletName,' +
        '(select ifnull(rates.bmf,0) from rates where rates.walletId = operations.walletId and DATE_FORMAT(date, "%Y-%m-%d") = DATE_FORMAT(operations.date, "%Y-%m-%d") limit 1) as bmf,' +
        '(select ifnull(rates.brokerage,0) from rates where rates.walletId = operations.walletId and DATE_FORMAT(date, "%Y-%m-%d") = DATE_FORMAT(operations.date, "%Y-%m-%d") limit 1) as brokerage,' +
        '(select ifnull(rates.emolument,0) from rates where rates.walletId = operations.walletId and DATE_FORMAT(date, "%Y-%m-%d") = DATE_FORMAT(operations.date, "%Y-%m-%d") limit 1) as emolument,' +
        '(select ifnull(rates.irrf,0) from rates where rates.walletId = operations.walletId and DATE_FORMAT(date, "%Y-%m-%d") = DATE_FORMAT(operations.date, "%Y-%m-%d") limit 1) as irrf,' +
        '(select ifnull(rates.otherCosts,0) from rates where rates.walletId = operations.walletId and DATE_FORMAT(date, "%Y-%m-%d") = DATE_FORMAT(operations.date, "%Y-%m-%d") limit 1) as otherCosts',
    );
    queryBuilder.from('operations', 'operations');
    queryBuilder.where('operations.walletId IN (:...ids)', {
      ids: walletIds.map(w => w.id),
    });
    queryBuilder.groupBy('date,operations.walletId');

    console.log(await queryBuilder.execute());

    return paginate<any>(queryBuilder, {
      page,
      limit,
    });

If I do await queryBuilder.execute() I can see some data but paginate result is empty.

{
  "items": [],
  "meta": {
    "totalItems": 74,
    "itemCount": 0,
    "itemsPerPage": 10,
    "totalPages": 8,
    "currentPage": 1
  },
  "links": {
    "first": "",
    "previous": "",
    "next": "",
    "last": ""
  }
}

See that it counts in totalItems but items is empty.

Any help?

EDIT:

Using queryBuilder.execute() or "queryBuilder.getRawMany()" will return data but queryBuilder.getManyAndCount() will not.

Add the ? on the route if the base route in options does not contain the ?

Add the ? on the route if the base route in options does not contain the ?

next: hasNextPage ? `${route}?page=${currentPage + 1}&limit=${limit}` : "",

let routes: IPaginationLinks;
if (route.include('?')) {
  routes = {
    first: hasFirstPage ? `${route}&limit=${limit}` : "",
    previous: hasPreviousPage ? `${route}&page=${currentPage - 1}&limit=${limit}` : "",
    next: hasNextPage ? `${route}&page=${currentPage + 1}&limit=${limit}` : "",
    last: hasLastPage ? `${route}&page=${totalPages}&limit=${limit}` : ""
  };
} else {
  routes = {
    first: hasFirstPage ? `${route}?limit=${limit}` : "",
    previous: hasPreviousPage ? `${route}?page=${currentPage - 1}&limit=${limit}` : "",
    next: hasNextPage ? `${route}?page=${currentPage + 1}&limit=${limit}` : "",
    last: hasLastPage ? `${route}?page=${totalPages}&limit=${limit}` : ""
  };
}

or

const quote = route.include('?') ? '&' : '?';
const  routes = {
    first: hasFirstPage ? `${route}${quote}limit=${limit}` : "",
    previous: hasPreviousPage ? `${route}${quote}page=${currentPage - 1}&limit=${limit}` : "",
    next: hasNextPage ? `${route}${quote}page=${currentPage + 1}&limit=${limit}` : "",
    last: hasLastPage ? `${route}${quote}page=${totalPages}&limit=${limit}` : ""
  };

Allow paginate for raw queries

For now the package only supports query builder usage for entity query buiders

async function paginateQueryBuilder<T>(
  queryBuilder: SelectQueryBuilder<T>,
  options: IPaginationOptions,
): Promise<Pagination<T>> {
  const [page, limit, route] = resolveOptions(options);

  const [items, total] = await queryBuilder
    .take(limit)
    .skip((page - 1) * limit)
    .getManyAndCount();

  return createPaginationObject<T>(items, total, page, limit, route);
}

We can discuss an way to use raw queries using something like:

  qb.limit(limit)
      .offset((page - 1) * limit)
      .getRawMany();

TS2314: Generic type 'IPaginationOptions<CustomMetaType>' requires 1 type argument(s).

3d8fcbe#diff-2433a58dd5b382f3ef0faf44d5ab97bf79428a0a1452d72934c9ca3c77a237bcR1 introduced new CustomMetaType generic on IPaginationOptions to support new optional metaTransformer method, but appears to be required whether that method is used or not. Ideally could be updated to make the generic type optional as well, defaulting to whatever interface should be used when metaTransformer is not defined.

Readme is unclear on how to use this, still reference old format without the provided generic type https://github.com/nestjsx/nestjs-typeorm-paginate/blame/2d108b00942b1ca4ecfcb4947e3232ddf305d704/README.md#L46

Next page url is shown on last page

When paginating we are given a url to next page, that is pretty good. However if you hit the last page, you are still given the url for next page which upon visiting shows empty data.


itemCount | 2
totalItems | 4
pageCount | 2
next | "http://localhost:8000/v1/user?page=3&limit=2"
previous | "http://localhost:8000/v1/user?page=1&limit=2"

As you can see in the above output, I have 4 data and is using limit to 2, so logically i should only have 2 pages. But if i visit the last page, i am still given a link to 3rd page

NestJS 8.x.x is not supported

Nothing to add really, wanted to upgrade NestJS to @8, but actually needed to stick to @7, the solution is to upgrade peerDependencies here

Counter incorrect on queries with groupBy

Hello all!

When making queries grouping items, the TypeORM getCount method used to count items on table apparently consider all items matching with where conditions only, ignoring grouping, example:

const now = new Date();
const start = startOfMonth(now).toISOString();
const end = endOfMonth(now).toISOString();

const queryBuilder = this.exampleRepository
  .createQueryBuilder()
  .select('name as customer, round(sum(total)::numeric, 2)::float as total')
  .groupBy('name')
  .where(`usage between '${start}' and '${end}'`)
  .orderBy('total', 'DESC');

return paginateRaw<T>(queryBuilder, paginationOptions);

This example fetch, for example, 7 items grouped by name and their total usage from 500 registers on database, instead of returning 7, count returns 500.

To work around the problem I did this:

async function countItemsForComplexQueryBuilder(
  queryBuilder: SelectQueryBuilder<any>,
) {
  const query = queryBuilder.getQuery();
  const connection = getConnection();

  const { count } = await connection
    .createQueryBuilder()
    .select('count(t.*)', 'count')
    .from(`(${query})`, 't')
    .getRawOne<{ count: string }>();

  return Number(count);
}

And used return of this function in counter key.

it might be interesting to add some option in the library to count the items following the idea as above. The idea is pertinent to add to the codebase?


Congrats for the project

yarn run build error

When I run the yarn run build command๏ผš

node_modules/nestjs-typeorm-paginate/dist/paginate.d.ts:1:22 - error TS2305: Module '"/node_modules/typeorm"' has no exported member 'FindConditions'.

1 import { Repository, FindConditions, FindManyOptions, SelectQueryBuilder } from "typeorm";
                       ~~~~~~~~~~~~~~

node_modules/nestjs-typeorm-paginate/dist/paginate.d.ts:1:38 - error TS2305: Module '"node_modules/typeorm"' has no exported member 'FindManyOptions'.

1 import { Repository, FindConditions, FindManyOptions, SelectQueryBuilder } from "typeorm";
                                       ~~~~~~~~~~~~~~~


Found 2 errors.

error Command failed with exit code 2.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

The pagination returns wrong totalItems, pageCount, next, previous page links

The pagination returns wrong totalItems, pageCount, next, previous page links even when coupled with a where clause.
When there are 4 rows in my table for user 1, and user 2

return await paginate<PayoutsEntity>(this.repo, options, {
      user_id: 2,
});

This should return totalItems: 2, pageCount: 2, next: /payments?page=1&limit=1, previous: ''

...but this is what i'm getting.
image
Extra optional parameters are not taken into account while the total pages are calculated? Why are total items showing 4 for user_id = 2 when it should be 2 instead.

Find options in paginate

//this not filtering, returning all rows
  async paginate(
    options: IPaginationOptions,
    user: User,
  ): Promise<Pagination<Car>> {
    const aux = await paginate<Car>(this.carRepository, options, { user });
    return aux;
  }

//this works
  async find(user: User) {
    return await this.carRepository.findAndCount({ where: { user } });
  }

am i using find options param correctly? Or is it a bug?

great lib btw :)

Add variable limit

Add variable limit to response.

Example:
{ "items": [ { "id": "8be4d71a-e76e-4ef1-8230-2c90e47f1eb1", "rol": "Gerencia", "createdAt": "2019-05-25T17:36:10.916Z", "updatedAt": "2019-05-25T17:56:38.152Z", "version": 4 }, { "id": "7e60ed59-0e8d-47ef-a863-5c0849107d25", "rol": "Administrador", "createdAt": "2019-05-25T23:39:31.811Z", "updatedAt": "2019-05-25T23:39:31.811Z", "version": 1 }, { "id": "542d7e39-b979-44ea-8e2c-04ff9e7d0228", "rol": "Administrador1", "createdAt": "2019-05-25T23:47:41.764Z", "updatedAt": "2019-05-25T23:47:41.764Z", "version": 1 } ], "itemCount": 3, "totalItems": 8, "pageCount": 3, "next": "http://localhost:3000/api/v1/admin/roles?limit=3?page=2&limit=3", "previous": "" }

Typeorm paginate does not work with addSelect

I have a query where I need to add a custom column using addSelect .addSelect('membership.commissionPercentage', 'commissionPercentage') and return paginated data but it does not work.

If I query result with queryBuilder.getRawMany() I get commissionPercentage but not with

return paginate<User>(queryBuilder, {
      page: query.queryOptions.page,
      limit: query.queryOptions.limit,
      route: query.queryOptions.route
    });

Limit not working when using multiple order by

    const page = 1;
    const limit = 25;
    const pocConnection = getConnection('default');
    const result =  pocConnection.getRepository(Candidates).createQueryBuilder('candidate')
                                        .leftJoinAndSelect('candidate.interviewSlots', 'interviewSlots')
                                        .where('candidate.currentRound > :currentRound', {currentRound: 2})
                                        .orderBy({
                                            'candidate.createdAt': 'DESC',
                                            'interviewSlots.createdAt': 'DESC'
                                        })
                                       
                                       
    const candidates  =  await paginate<Candidates>(result, {
        page,
        limit,
    });
    return candidates;

The following code returns 5 items, if I remove 'interviewSlots.createdAt': 'DESC' from orderBy it works fine

Wrong page counting

Hi. I've been using this lib in hobby project and faced the wrong page counting situation.

ScreenShot
Total Items = 11;
Default limit = 10;
So there are supposed to be two page ( 0, 1) but there is only one.

I can probably try to fix it :p
Also I have a question, pagination should work something like:
71 items means we have 8 pages, where 8th page return array of single element.

Now it returns last 10 last items;

Cursor-based pagination

Hello
As we all know offset and limit based pagination have performance issue in large amount of data.
I think the best solution is Cursor-based pagination.
Do you have any plane to implement this type of pagination?

PaginateRaw doesn't work well with joins.

PaginateRaw (and PaginateRawAndEntities) use .limit() and .offset() instead of .take() and .skip(), which cause some issues when using joins. Is there any particular reason why PaginateRaw uses limit/offset over take/skip?

ER_BAD_FIELD_ERROR: Unknown column 'distinctAlias.operations_id' in 'field list'

Hello!

I'm trying to make an aggregate query and I'm having this error.

ER_BAD_FIELD_ERROR: Unknown column 'distinctAlias.operations_id' in 'field list'

Of course that operations.id doesn't exists because I'm not selecting it.

Check my query:

const queryBuilder = await Operation.createQueryBuilder('operations');
    queryBuilder.select(
      'DATE_FORMAT(operations.date, "%Y-%m-%d") as date,' +
        'SUM(operations.numberOfContracts) as numberOfContracts, SUM(operations.value) as value,' +
        'wallets.name as walletName, ifnull(SUM(rates.bmf),0) as bmf, ifnull(SUM(rates.brokerage),0) as brokerage,' +
        'ifnull(SUM(rates.emolument),0) as emolument, ifnull(SUM(rates.irrf),0) as irrf, ifnull(SUM(rates.otherCosts),0) as otherCosts',
    );
    queryBuilder.innerJoin('operations.wallet', 'wallet');
    queryBuilder.leftJoin('wallet.rates', 'rates');
    queryBuilder.where('wallet.userId = :userId', { userId: user.id });
    queryBuilder.groupBy('date, operations.walletId');

If I add operations.id as operations_id to the select, then I got this:

QueryFailedError: ER_WRONG_FIELD_WITH_GROUP: Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'database.operations.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

The last error will desapear if I add operations.id to the group by... but, the returned list will be empty.

I don't know what I'm doing wrong, I'm not a sql expert.

Could you help me? thank you!

All versions from 2.0.x have missing `dist` folder

I just tried to update my version from 1.0.3 to 2.0.2 and I realized the project was failing. I tried with 2.0.1 and also with 2.0.0 and the result is the same: there is no dist folder inside the node_modules/nestjs-typeorm-paginate folder.

image

I wanted to ugrade to version 2.x as I'm experiencing the same problem described here: #258.

orderBy in option not working

  const filterOption = {
      relations: ['someRelation'], // works well
      where: {}, //works well
      orderBy:{ created_at: 'desc'} //not working
    };

return paginate(this.repo, options, filterOption);

am not sure is orderBy can use with this searchOptions ?

currentPage turn to string which causes problems in the links

Hello ,
i have 3 items and i want every page to have 1 item but as u can see the next link has page 21 which should be 2
image

i noticed that when it passed nestjs Query decorator turns to string again even though we typed it as number

@Query('limit') limit: number = 10

 console.log(typeof limit) // string

Offset not working in current npm version

I noticed that the source code of the version which is installed via npm is not the one in this repo. Both package.json state that it's version 1.0.0.
But in the one installed via npm the offset is set: queryBuilder.offset(page) and not .offset(page * limit).

Can you update that? Thanks!

Underscore keys for meta

Is it possible to give meta keys underscore separator to be more consistent with the rest of our API responses?

Example:

"meta": {
    "item_count": 10,
    "total_items": 20,
    "items_per_page": 10,
    "total_pages": 5,
    "current_page": 2
  }

QueryFailedError: OFFSET must not be negative

I just upgraded to 2.0.3 and got a run time error when using paginate.

[Nest] 13668   - 04/14/2020, 11:21:00 AM   [ExceptionsHandler] OFFSET must not be negative +79860ms
QueryFailedError: OFFSET must not be negative
    at new QueryFailedError (C:\Users\Jeremy\Desktop\zl\im\active_repo\should\im\src\error\QueryFailedError.ts:9:9)
    at Query.<anonymous> (C:\Users\Jeremy\Desktop\zl\im\active_repo\should\im\src\driver\postgres\PostgresQueryRunner.ts:178:30)
    at Query.handleError (C:\Users\Jeremy\Desktop\zl\im\active_repo\should\im\node_modules\pg\lib\query.js:138:19)
    at Connection.connectedErrorMessageHandler (C:\Users\Jeremy\Desktop\zl\im\active_repo\should\im\node_modules\pg\lib\client.js:223:17)
    at Connection.emit (events.js:315:20)
    at Socket.<anonymous> (C:\Users\Jeremy\Desktop\zl\im\active_repo\should\im\node_modules\pg\lib\connection.js:120:12)
    at Socket.emit (events.js:315:20)
    at addChunk (_stream_readable.js:297:12)
    at readableAddChunk (_stream_readable.js:273:9)
    at Socket.Readable.push (_stream_readable.js:214:10)

Here is the only code I am running

    // options = { page: 0, limit: 10 }
    const queryBuilder = this.posRepo.createQueryBuilder('position').where(`position.listed = true`);
    return await paginate<Position>(queryBuilder, options); // <- Error happens here

Was there a breaking change I am unaware of?

I tried my code on version 1.0.3 and verified I am not getting an error.

Allow configuration of case naming strategy on meta

Proposed feature change

The meta object item should be configurable to allow API with other naming cases (especially snake_case) to use pagination and maintain consistency with the rest of their strategy.

Details

Allow a configuration of paginate to return the meta object with snake casing:

  "meta": {
    "item_count": 10,
    "total_items": 20,
    "items_per_page": 10,
    "total_pages": 5,
    "current_page": 2
  },

The current behavior can be maintain using default config values


note: only meta is relevant, since there are no multi word keys in the other return objects

Make nestjs-typeorm-paginate responses return same type as @nestjs/crud

I think it would be a good idea (albeit a breaking change) that responses follow the same naming convention as the ones returned by nestjs/crud. We use both in the same project and we had to rely on using an interceptor to have consistent responses.

import {
  CallHandler,
  ExecutionContext,
  Injectable,
  NestInterceptor,
} from '@nestjs/common';
import { GetManyDefaultResponse } from '@nestjsx/crud';
import { Pagination } from 'nestjs-typeorm-paginate';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';

@Injectable()
export class PaginateTransformInterceptor<T>
  implements NestInterceptor<Pagination<T>, GetManyDefaultResponse<T>> {
  intercept(
    context: ExecutionContext,
    next: CallHandler<Pagination<T>>,
  ): Observable<GetManyDefaultResponse<T>> {
    return next.handle().pipe(
      map(data => ({
        count: data.itemCount,
        data: data.items,
        pageCount: data.itemCount,
        page: data.pageCount,
        total: data.totalItems,
      })),
    );
  }
}

pagenate(querybuilder, options) doesn't work for me

Hello

{
    "items": [
        ...
    ],
    "meta": {
        "totalItems": 22,
        "itemCount": 9,
        "itemsPerPage": "10",
        "totalPages": 3,
        "currentPage": "1"
    }
}

I get an outcome like this. I guessed itemCount should same with itemsPerPage.
Here is my service code.

async findPaginatedBundles(
    options: IPaginationOptions,
  ): Promise<Pagination<Bundle>> {
    const queryBuilder = this.bundleRepository.createQueryBuilder('bundle');
    await queryBuilder
      .leftJoinAndSelect('bundle.articles', 'article')
      .orderBy({ 'bundle.id': 'DESC' })
      .addOrderBy('article.id')
      .getMany();
    return await paginate<Bundle>(queryBuilder, options);
}

And I found it does work when I use repository.
like

return await paginate<Bundle>(this.bundleRepository, options, {
      relations: ['articles'],
      where: { delete_date: null },
      order: {
        id: 'DESC',
        // I need articles should be ordered by asc
      },
});

However since typeorm doesn't support ordering relations loaded with find's "relations" option, using paginate method with queryBuilder is only way I can choose.

Is there anyone can help with this problem?

Unable to mock the paginate<T> method

Hi, thanks for the good work !

I use this module in several pages but i can't find a way to properly mock the paginate method with jest

I've tried many ways, the nearest i think is that one :

const result =  []
jest.mock('nestjs-typeorm-paginate', () => {
        return jest.fn().mockImplementation(() => {
          return {paginate: <T>(repo, options) => result};
        });
      });

but my mock is ignored,

Could you please tell me the best way to mock that ?

Thanks !

GraphQL Support

Is there any way to use this with GraphQL?
Currently, i am not able to select the correct Query Return Object

Page 0 and 1 return the same data

In the README the default value for page is specified as 0. So I thought pages were counted from 0 onward. However when using 0 and 1 as page number I get the same result (in fact any value for page less than 1 seems to return the first page). Its actually when I use page 2 that I get the next page.

Just wondering if this is intended and what is the behavior for page 0.

Route link of the first page missing page param.

I just tried the package. It looks very good.

But unfortunately, i just tested it and in the routes links, the "first" is not correct.
"first": "/client/paginated?limit=3",
The page parameter is missing.

Here is the received result a little more expanded.

    "meta": {
        "totalItems": 8,
        "itemCount": 3,
        "itemsPerPage": 3,
        "totalPages": 3,
        "currentPage": 2
    },
    "links": {
        "first": "/client/paginated?limit=3",
        "previous": "/client/paginated?page=1&limit=3",
        "next": "/client/paginated?page=3&limit=3",
        "last": "/client/paginated?page=3&limit=3"
    }

I basically copy pasted the example of the readme file in a new nestjs project to test the package.

Here is the code that i used to try the package: sample-nestjs-typeorm-paginate

Repository<MongoRepository<User>>>

Hello i have following code


  async paginate(options: IPaginationOptions): Promise<Pagination<MongoRepository<User>>> {
        // return paginate<User>(this.usersRepository, options);
        return paginate<MongoRepository<User>>(this.usersRepository, {});
    }

But I'm not able to use with mongo Repository this is what i get:
Argument of type 'MongoRepository' is not assignable to parameter of type 'Repository<MongoRepository>' how to fix the part with Repository

Paginate by id

Instead of paginating via page, use entity id instead to get the next 10 of object id

Searching with Where Or clause not working

 return paginate<ProductEntity>(this.repostiory, options, {
        where: [
          {
            title: Like(`%${search}%`),
          },
          {
            description: Like(`%${search}%`),
          },
          {
            price: Like(`%${search}%`),
          },
        ],
      });

This is the syntax to use to run a search on more than one field.

Error Received:

QueryFailedError: operator does not exist: numeric ~~ unknown
    at new QueryFailedError (/node_modules/typeorm/error/QueryFailedError.js:11:28)
    at Query.callback (/node_modules/typeorm/driver/postgres/PostgresQueryRunner.js:176:38)
    at Query.handleError (/node_modules/pg/lib/query.js:145:17)
    at Connection.connectedErrorMessageHandler (/node_modules/pg/lib/client.js:214:17)
    at Connection.emit (events.js:315:20)
    at Socket.<anonymous> (/node_modules/pg/lib/connection.js:134:12)
    at Socket.emit (events.js:315:20)
    at addChunk (_stream_readable.js:295:12)
    at readableAddChunk (_stream_readable.js:271:9)
    at Socket.Readable.push (_stream_readable.js:212:10)

Paginate arrays feature.

Hi. I want to request feature to paginate arrays of entities that already somehow were extracted from database.
I see this something like this:

import { paginateArray, Pagination, IPaginationOptions } from 'nestjs-typeorm-paginate';
//
//
const usersArray : Array<User> = [{id: 1. name: "first}, ...]; 
return paginateArray<Users>(usersArray, options);

This would be useful if there are some data that needs to be modified somehow, before being paginatied.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.