Skip to content

Commit a556963

Browse files
authored
Merge branch 'master' into bugfix/mongoose-query-service-accept-any-ids
2 parents b364870 + edafa5f commit a556963

File tree

74 files changed

+284
-294
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+284
-294
lines changed

CHANGELOG.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -880,7 +880,7 @@
880880

881881
### Bug Fixes
882882

883-
* **typeorm, #954:** Filtering on relations with pagination ([#977](https://github.com/tripss/nestjs-query/issues/977)) ([f5a6374](https://github.com/tripss/nestjs-query/commit/f5a6374f6e22470f63ef6257f7271c818ed09321)), closes [#954](https://github.com/tripss/nestjs-query/issues/954) [#954](https://github.com/tripss/nestjs-query/issues/954) [#954](https://github.com/tripss/nestjs-query/issues/954) [#954](https://github.com/tripss/nestjs-query/issues/954)
883+
* **typeorm, #954:** Filtering on relations with pagination ([#977](https://github.com/tripss/nestjs-query/issues/977)) ([f5a6374](https://github.com/tripss/nestjs-query/commit/f5a6374f6e22470f63ef6257f7271c818ed09321)), closes [#954](https://github.com/doug-martin/nestjs-query/issues/954) [#954](https://github.com/doug-martin/nestjs-query/issues/954) [#954](https://github.com/doug-martin/nestjs-query/issues/954) [#954](https://github.com/doug-martin/nestjs-query/issues/954)
884884

885885

886886

documentation/docs/concepts/queries.mdx

-9
Original file line numberDiff line numberDiff line change
@@ -170,15 +170,6 @@ const q: Query<MyClass> = {
170170
</TabItem>
171171
</Tabs>
172172

173-
:::note
174-
When using filters on relations with `typeorm` in combination with paging, performance can be degraded on large result
175-
sets. For more info see this [issue](https://github.com/tripss/nestjs-query/issues/954)
176-
177-
In short two queries will be executed:
178-
* The first one fetching a distinct list of primary keys with paging applied.
179-
* The second uses primary keys from the first query to fetch the actual records.
180-
:::
181-
182173
---
183174

184175
## Sorting

documentation/docs/graphql/dataloaders.mdx

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ title: Dataloaders
33
sidebar_label: Dataloaders
44
---
55

6-
Nestjs-query integrates a standard implementation of [dataloaders](https://www.npmjs.com/package/dataloader/v/2.1.0). Dataloaders are there to solve the `n+1`. Sometimes the default implementation can fail, for example when asynchronous [custom authorizers](./authorization.mdx#custom-authorizer) are used and the `n+1` problem occurs again despite using dataloaders. Then it may be useful to configure the default implementation of the dataloader, for example to pass a custom batch scheduler.
6+
Nestjs-query integrates a standard implementation of [dataloaders](https://www.npmjs.com/package/dataloader/v/2.2.2). Dataloaders are there to solve the `n+1`. Sometimes the default implementation can fail, for example when asynchronous [custom authorizers](./authorization.mdx#custom-authorizer) are used and the `n+1` problem occurs again despite using dataloaders. Then it may be useful to configure the default implementation of the dataloader, for example to pass a custom batch scheduler.
77

8-
The following example demonstrates how to configure the generated dataloaders. For more information about the dataloader configuration, see the [dataloader documentation](https://www.npmjs.com/package/dataloader/v/2.1.0).
8+
The following example demonstrates how to configure the generated dataloaders. For more information about the dataloader configuration, see the [dataloader documentation](https://www.npmjs.com/package/dataloader/v/2.2.2).
99

1010
```ts title="app.module.ts"
1111
import { Module } from '@nestjs/common';

documentation/docs/graphql/dtos.mdx

+3-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ title: DTOs
55
import Tabs from '@theme/Tabs';
66
import TabItem from '@theme/TabItem';
77

8-
The `query-graphql` package leverages most decorators from [`@nestjs/graphql`](https://docs.nestjs.com/graphql/quick-start) and [TypeGraphQL](https://typegraphql.ml), with the exception of `FilterableField`.
8+
The `query-graphql` package leverages most decorators from [`@nestjs/graphql`](https://docs.nestjs.com/graphql/quick-start) and [TypeGraphQL](https://typegraphql.com), with the exception of `FilterableField`.
99

1010
## `@FilterableField`
1111

@@ -148,8 +148,7 @@ export class TodoItemDTO {
148148

149149
## `@IDField`
150150

151-
By default `nestjs-query` uses the default graphql `ID` scalar, if you need to use a different `graphql` `scalar`
152-
type you can `@IDField` decorator. `nestjs-query` will `scalar` type passed to the `@IDField` for all auto-generated
151+
By default `nestjs-query` uses the default graphql `ID` scalar, if you need to use a different `graphql` `scalar` type you can use `@IDField` decorator. `nestjs-query` will use that `scalar` type passed to the `@IDField` for all auto-generated
153152
`query` and `mutation` endpoints that rely on an input for the `id` (e.g. `findById`, `updateOne`, `deleteOne`).
154153

155154
:::note
@@ -426,7 +425,7 @@ You can override the default `pagingStrategy` to one of the following alternativ
426425
* `OFFSET` - sets paging to allow `limit` and `offset` fields, and returns an `OffsetConnection`.
427426
* `NONE` - turn off all paging and always return an `ArrayConnection`.
428427
429-
When using the `OFFSET` strategy your the paging arguments for a many query will accept a `limit` and/or `offset`.
428+
When using the `OFFSET` strategy your paging arguments for a many query will accept a `limit` and/or `offset`.
430429
This will also change the return type from a `CursorConnection` to an `OffsetConnection`.
431430
432431
```ts title="todo-item.dto.ts" {5}

documentation/docs/graphql/queries/endpoints.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ All examples below assume that a connection is returned but filtering and sortin
9999
strategies. To read how to page collections read the [paging docs](./paging)
100100
:::
101101

102-
By default if you do not provided an arguments you can query for all records.
102+
By default if you do not provided an arguments it will uses a default value for [the page size](../dtos#result-page-size) and for the [sorting](../dtos/#default-sort).
103103

104104
<Tabs
105105
defaultValue="graphql"

documentation/docs/graphql/queries/filtering.mdx

+7-7
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ title: Filtering
55
import Tabs from '@theme/Tabs';
66
import TabItem from '@theme/TabItem';
77

8-
Filtering in `query-graphql` has has an object based syntax
8+
Filtering in `nestjs-query` has an object based syntax.
99

1010
For a full reference of filter operations [see filter reference](../../concepts/queries.mdx#filter-reference)
1111

@@ -88,20 +88,20 @@ The following example filters for all todoItems that are marked completed.
8888

8989
## Setting the generated filter-type depth
9090

91-
When querying the default filter is one level deep. You can specify the generated filter-type depth by using the QueryOptions decorator on your DTO.
91+
When querying the default filter is one level deep. You can specify the generated filter-type depth by using the `QueryOptions` decorator on your DTO.
9292

93-
You can find the documentation and an example in the [QueryOptions reference](../dtos.mdx#generated-filter-type-depth).
93+
You can find the documentation and an example in the [`QueryOptions` reference](../dtos.mdx#generated-filter-type-depth).
9494

9595

9696
## Setting a default filter
9797

98-
When querying the default filter is empty. You can specify a default filter by using the QueryOptions decorator on your DTO.
98+
When querying the default filter is empty. You can specify a default filter by using the `QueryOptions` decorator on your DTO.
9999

100-
You can find the documentation and an example in the [QueryOptions reference](../dtos.mdx#setting-a-default-filter).
100+
You can find the documentation and an example in the [`QueryOptions` reference](../dtos.mdx#setting-a-default-filter).
101101

102102

103103
## Setting allowed boolean expressions
104104

105-
When filtering you can provide and and or expressions to provide advanced filtering. You can turn off either by using the QueryOptions decorator on your DTO.
105+
When filtering you can provide `and` and `or` expressions to provide advanced filtering. You can turn off either by using the `QueryOptions` decorator on your DTO.
106106

107-
You can find the documentation and an example in the [QueryOptions reference](../dtos.mdx#allowed-boolean-expressions).
107+
You can find the documentation and an example in the [`QueryOptions` reference](../dtos.mdx#allowed-boolean-expressions).

documentation/docs/graphql/resolvers.mdx

+3-3
Original file line numberDiff line numberDiff line change
@@ -714,7 +714,7 @@ export class TodoItemResolver extends CRUDResolver(TodoItemDTO, {
714714
If you find yourself in a situation where you want to override an endpoint name you can use the `one.name` or `many.name` options to override
715715

716716
:::note
717-
These options are available for the `create`, `read`, `update`, and 'delete' endpoints.
717+
These options are available for the `create`, `read`, `update`, and `delete` endpoints.
718718
:::
719719

720720
In this example we'll change the `todoItem` query to `findTodoItem` and the `todoItems` endpoint to `queryForTodoItems`.
@@ -967,7 +967,7 @@ completedTodoItems(
967967
sorting: [TodoItemSort!] = []
968968
): TodoItemConnection!
969969
```
970-
Notice how there is not a query arg but instead the you see the fields of `TodoItemQuery` that is because we used
970+
Notice how there is not a `query` arg but instead you see the fields of `TodoItemQuery`, that is because we used
971971
`@Args` without a name and added the `@ArgsType` decorator to the `TodoItemQuery`.
972972
973973
The next piece is
@@ -983,7 +983,7 @@ const filter: Filter<TodoItemDTO> = {
983983
Here we do a shallow copy of the `filter` and add `completed: { is: true }`. This will override any completed arguments
984984
that an end user may have provided to ensure we always query for completed todos.
985985
986-
Finally we call create our connection response by using the `createFromPromise` method on the connection.
986+
Finally we create our connection response by using the `createFromPromise` method on the connection.
987987
988988
```ts
989989
// call the original queryMany method with the new query

documentation/docs/persistence/services.mdx

+4-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ title: Services
44
import Tabs from '@theme/Tabs';
55
import TabItem from '@theme/TabItem';
66

7-
`@nestjs-query` provides a common interface to use difference ORMs inorder to query and mutate your data.
7+
`@nestjs-query` provides a common interface to use different ORMs in order to query and mutate your data.
88

99
The following ORMs are supported out of the box.
1010

@@ -170,7 +170,7 @@ export class TodoItemEntity implements Base {
170170

171171
### Module
172172

173-
The `nestjs-query` `typeorm`, `sequelize`, `mongoose`, and 'typegoose' packages provide a module that will add providers
173+
The `nestjs-query` `typeorm`, `sequelize`, `mongoose`, and `typegoose` packages provide a module that will add providers
174174
to inject auto-created `QueryServices` using the `@InjectQueryService` decorator.
175175

176176
In order to use the decorator you will need to use the module that comes with the `nestjs-query` orm module providing it your entities that you want the services created for.
@@ -378,7 +378,7 @@ try {
378378

379379
To perform an `aggregate` query you can use the `aggregate` method which accepts a `Filter` and `AggregateQuery`.
380380

381-
Supported aggregates are `count`, 'sum', 'avg', `min` and `max`.
381+
Supported aggregates are `count`, `sum`, `avg`, `min` and `max`.
382382

383383
In this example we'll aggregate on all records.
384384

@@ -672,7 +672,7 @@ This section only applies when you combine your DTO and entity and are using Typ
672672

673673
When your DTO and entity are the same class and you have relations defined, you should not decorate your the relations in the DTO with `@Field` or `@FilterableField`.
674674

675-
Instead decorate the class with `@CursorConnection`, `@OffsetConnection`, '@UnPagedRelation' or `@Relation`.
675+
Instead decorate the class with `@CursorConnection`, `@OffsetConnection`, `@UnPagedRelation` or `@Relation`.
676676

677677
### Example
678678

examples/all-paging/e2e/fixtures.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
import { Connection } from 'typeorm'
1+
import { DataSource } from 'typeorm'
22

33
import { executeTruncate } from '../../helpers'
44
import { SubTaskEntity } from '../src/sub-task/sub-task.entity'
55
import { TagEntity } from '../src/tag/tag.entity'
66
import { TodoItemEntity } from '../src/todo-item/todo-item.entity'
77

88
const tables = ['todo_item', 'sub_task', 'tag']
9-
export const truncate = async (connection: Connection): Promise<void> => executeTruncate(connection, tables)
9+
export const truncate = async (dataSource: DataSource): Promise<void> => executeTruncate(dataSource, tables)
1010

11-
export const refresh = async (connection: Connection): Promise<void> => {
12-
await truncate(connection)
11+
export const refresh = async (dataSource: DataSource): Promise<void> => {
12+
await truncate(dataSource)
1313

14-
const todoRepo = connection.getRepository(TodoItemEntity)
15-
const subTaskRepo = connection.getRepository(SubTaskEntity)
16-
const tagsRepo = connection.getRepository(TagEntity)
14+
const todoRepo = dataSource.getRepository(TodoItemEntity)
15+
const subTaskRepo = dataSource.getRepository(SubTaskEntity)
16+
const tagsRepo = dataSource.getRepository(TagEntity)
1717

1818
const urgentTag = await tagsRepo.save({ name: 'Urgent' })
1919
const homeTag = await tagsRepo.save({ name: 'Home' })

examples/all-paging/e2e/sub-task.resolver.spec.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { INestApplication, ValidationPipe } from '@nestjs/common'
22
import { Test } from '@nestjs/testing'
33
import { CursorConnectionType } from '@ptc-org/nestjs-query-graphql'
44
import request from 'supertest'
5-
import { Connection } from 'typeorm'
5+
import { DataSource } from 'typeorm'
66

77
import { AppModule } from '../src/app.module'
88
import { SubTaskDTO } from '../src/sub-task/dto/sub-task.dto'
@@ -29,10 +29,10 @@ describe('SubTaskResolver (limitOffset - e2e)', () => {
2929
)
3030

3131
await app.init()
32-
await refresh(app.get(Connection))
32+
await refresh(app.get(DataSource))
3333
})
3434

35-
afterAll(() => refresh(app.get(Connection)))
35+
afterAll(() => refresh(app.get(DataSource)))
3636

3737
const subTasks = [
3838
{ id: '1', title: 'Create Nest App - Sub Task 1', completed: true, description: null, todoItemId: '1' },

examples/all-paging/e2e/tag.resolver.spec.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { INestApplication, ValidationPipe } from '@nestjs/common'
22
import { Test } from '@nestjs/testing'
33
import { CursorConnectionType, OffsetConnectionType } from '@ptc-org/nestjs-query-graphql'
44
import request from 'supertest'
5-
import { Connection } from 'typeorm'
5+
import { DataSource } from 'typeorm'
66

77
import { AppModule } from '../src/app.module'
88
import { TagDTO } from '../src/tag/dto/tag.dto'
@@ -30,10 +30,10 @@ describe('TagResolver (limitOffset - e2e)', () => {
3030
)
3131

3232
await app.init()
33-
await refresh(app.get(Connection))
33+
await refresh(app.get(DataSource))
3434
})
3535

36-
afterAll(() => refresh(app.get(Connection)))
36+
afterAll(() => refresh(app.get(DataSource)))
3737

3838
const tags = [
3939
{ id: '1', name: 'Urgent' },

examples/all-paging/e2e/todo-item.resolver.spec.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { INestApplication, ValidationPipe } from '@nestjs/common'
22
import { Test } from '@nestjs/testing'
33
import { CursorConnectionType, OffsetConnectionType } from '@ptc-org/nestjs-query-graphql'
44
import request from 'supertest'
5-
import { Connection } from 'typeorm'
5+
import { DataSource } from 'typeorm'
66

77
import { AppModule } from '../src/app.module'
88
import { SubTaskDTO } from '../src/sub-task/dto/sub-task.dto'
@@ -31,7 +31,7 @@ describe('TodoItemResolver (limitOffset - e2e)', () => {
3131
)
3232

3333
await app.init()
34-
await refresh(app.get(Connection))
34+
await refresh(app.get(DataSource))
3535
})
3636

3737
const todoItems = [
@@ -42,7 +42,7 @@ describe('TodoItemResolver (limitOffset - e2e)', () => {
4242
{ id: '5', title: 'How to create item With Sub Tasks', completed: false, description: null }
4343
]
4444

45-
afterAll(() => refresh(app.get(Connection)))
45+
afterAll(() => refresh(app.get(DataSource)))
4646

4747
describe('find one', () => {
4848
it(`should find a todo item by id`, () =>

examples/auth/e2e/fixtures.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Connection } from 'typeorm'
1+
import { DataSource } from 'typeorm'
22

33
import { executeTruncate } from '../../helpers'
44
import { SubTaskEntity } from '../src/sub-task/sub-task.entity'
@@ -7,15 +7,15 @@ import { TodoItemEntity } from '../src/todo-item/todo-item.entity'
77
import { UserEntity } from '../src/user/user.entity'
88

99
const tables = ['todo_item', 'sub_task', 'tag', 'user']
10-
export const truncate = async (connection: Connection): Promise<void> => executeTruncate(connection, tables)
10+
export const truncate = async (dataSource: DataSource): Promise<void> => executeTruncate(dataSource, tables)
1111

12-
export const refresh = async (connection: Connection): Promise<void> => {
13-
await truncate(connection)
12+
export const refresh = async (dataSource: DataSource): Promise<void> => {
13+
await truncate(dataSource)
1414

15-
const userRepo = connection.getRepository(UserEntity)
16-
const todoRepo = connection.getRepository(TodoItemEntity)
17-
const subTaskRepo = connection.getRepository(SubTaskEntity)
18-
const tagsRepo = connection.getRepository(TagEntity)
15+
const userRepo = dataSource.getRepository(UserEntity)
16+
const todoRepo = dataSource.getRepository(TodoItemEntity)
17+
const subTaskRepo = dataSource.getRepository(SubTaskEntity)
18+
const tagsRepo = dataSource.getRepository(TagEntity)
1919

2020
const users = await userRepo.save([
2121
{ username: 'nestjs-query', password: '123' },

examples/auth/e2e/sub-task.resolver.spec.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Test } from '@nestjs/testing'
33
import { AggregateResponse } from '@ptc-org/nestjs-query-core'
44
import { CursorConnectionType } from '@ptc-org/nestjs-query-graphql'
55
import request from 'supertest'
6-
import { Connection } from 'typeorm'
6+
import { DataSource } from 'typeorm'
77

88
import { AppModule } from '../src/app.module'
99
import { AuthService } from '../src/auth/auth.service'
@@ -33,10 +33,10 @@ describe('SubTaskResolver (auth - e2e)', () => {
3333
)
3434

3535
await app.init()
36-
await refresh(app.get(Connection))
36+
await refresh(app.get(DataSource))
3737
})
3838

39-
afterAll(() => refresh(app.get(Connection)))
39+
afterAll(() => refresh(app.get(DataSource)))
4040

4141
beforeEach(async () => {
4242
const authService = app.get(AuthService)

examples/auth/e2e/tag.resolver.spec.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Test } from '@nestjs/testing'
33
import { AggregateResponse, getQueryServiceToken, QueryService } from '@ptc-org/nestjs-query-core'
44
import { CursorConnectionType } from '@ptc-org/nestjs-query-graphql'
55
import request from 'supertest'
6-
import { Connection } from 'typeorm'
6+
import { DataSource } from 'typeorm'
77

88
import { AppModule } from '../src/app.module'
99
import { AuthService } from '../src/auth/auth.service'
@@ -41,10 +41,10 @@ describe('TagResolver (auth - e2e)', () => {
4141
)
4242

4343
await app.init()
44-
await refresh(app.get(Connection))
44+
await refresh(app.get(DataSource))
4545
})
4646

47-
afterAll(() => refresh(app.get(Connection)))
47+
afterAll(() => refresh(app.get(DataSource)))
4848

4949
beforeEach(async () => {
5050
const authService = app.get(AuthService)

examples/auth/e2e/todo-item.resolver.spec.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Test } from '@nestjs/testing'
33
import { AggregateResponse, getQueryServiceToken, QueryService } from '@ptc-org/nestjs-query-core'
44
import { CursorConnectionType } from '@ptc-org/nestjs-query-graphql'
55
import request from 'supertest'
6-
import { Connection } from 'typeorm'
6+
import { DataSource } from 'typeorm'
77

88
import { AppModule } from '../src/app.module'
99
import { AuthService } from '../src/auth/auth.service'
@@ -45,7 +45,7 @@ describe('TodoItemResolver (auth - e2e)', () => {
4545
)
4646

4747
await app.init()
48-
await refresh(app.get(Connection))
48+
await refresh(app.get(DataSource))
4949
})
5050

5151
beforeEach(async () => {
@@ -54,7 +54,7 @@ describe('TodoItemResolver (auth - e2e)', () => {
5454
user3JwtToken = (await authService.login({ username: 'nestjs-query-3', id: 3 })).accessToken
5555
})
5656

57-
afterAll(() => refresh(app.get(Connection)))
57+
afterAll(() => refresh(app.get(DataSource)))
5858

5959
describe('find one', () => {
6060
it('should require authorization token', () =>

examples/basic/e2e/fixtures.ts

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
import { Connection } from 'typeorm'
1+
import { DataSource } from 'typeorm'
22

33
import { executeTruncate } from '../../helpers'
44
import { SubTaskEntity } from '../src/sub-task/sub-task.entity'
55
import { TagEntity } from '../src/tag/tag.entity'
66
import { TodoItemEntity } from '../src/todo-item/todo-item.entity'
77

88
const tables = ['todo_item', 'sub_task', 'tag']
9-
export const truncate = async (connection: Connection): Promise<void> => executeTruncate(connection, tables)
9+
export const truncate = async (dataSource: DataSource): Promise<void> => executeTruncate(dataSource, tables)
1010

11-
export const refresh = async (connection: Connection): Promise<void> => {
12-
await truncate(connection)
11+
export const refresh = async (dataSource: DataSource): Promise<void> => {
12+
await truncate(dataSource)
1313

14-
const todoRepo = connection.getRepository(TodoItemEntity)
15-
const subTaskRepo = connection.getRepository(SubTaskEntity)
16-
const tagsRepo = connection.getRepository(TagEntity)
14+
const todoRepo = dataSource.getRepository(TodoItemEntity)
15+
const subTaskRepo = dataSource.getRepository(SubTaskEntity)
16+
const tagsRepo = dataSource.getRepository(TagEntity)
1717

1818
const urgentTag = await tagsRepo.save({ name: 'Urgent' })
1919
const homeTag = await tagsRepo.save({ name: 'Home' })

0 commit comments

Comments
 (0)