Skip to content

Commit b59824e

Browse files
committed
docs: describe errors, filter operators & aliases in 9.0.0 release notes
1 parent 2f18e93 commit b59824e

File tree

1 file changed

+286
-17
lines changed

1 file changed

+286
-17
lines changed

docs/releases/9.0.0.md

Lines changed: 286 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,19 @@
44

55
- [What's new?](#whats-new)
66
- [🛑 resolver creation (factory)](#🛑-resolver-creation-factory)
7-
- [🛑 error handling (payload.error, mongoose validation)](#🛑-error-handling-payloaderror-mongoose-validation)
7+
- [Mutations got `error: ErrorInterface` field in theirs payload for better error handling](#mutations-got-error-errorinterface-field-in-theirs-payload-for-better-error-handling)
8+
- [Added a new `ValidationError`](#added-a-new-validationerror)
89
- [Improvements](#improvements)
910
- [Now `_id` field can be of any type (Int, String, Object)](#now-_id-field-can-be-of-any-type-int-string-object)
10-
- [🛑 recursive `filter._operators`](#🛑-recursive-filter_operators)
11-
- [🛑 better alias & projection support for nested embedded documents](#🛑-better-alias--projection-support-for-nested-embedded-documents)
12-
- [🛑 typescript improvements for resolvers](#🛑-typescript-improvements-for-resolvers)
11+
- [Add nested fields support, new operators `regex`, `exists` for `filter._operators`](#add-nested-fields-support-new-operators-regex-exists-for-filter_operators)
12+
- [Better alias support for nested embedded fields](#better-alias-support-for-nested-embedded-fields)
1313
- [Performance improvements](#performance-improvements)
14+
- [Added projection for nested embedded documents](#added-projection-for-nested-embedded-documents)
1415
- [Added new `dataLoader` & `dataLoaderMany` resolvers](#added-new-dataloader--dataloadermany-resolvers)
1516
- [Add `lean: boolean` option to query resolvers](#add-lean-boolean-option-to-query-resolvers)
1617
- [Breaking changes](#breaking-changes)
1718
- [In resolver `updateById` was changed its input args](#in-resolver-updatebyid-was-changed-its-input-args)
19+
- [`createMany` resolver now validates all records before save](#createmany-resolver-now-validates-all-records-before-save)
1820
- [Some generated types were renamed](#some-generated-types-were-renamed)
1921
- [Misc](#misc)
2022
- [Thanks](#thanks)
@@ -33,16 +35,204 @@
3335
- feat: added new function `composeMongoose` which generates TypeComposer without resolvers. Now Resolvers can be generated on-demand in such way `PostTC.mongooseResolvers.findMany()` (before was `PostTC.getResolver('findMany')`)
3436
- Improve Typescript definitions for resolvers
3537

36-
### 🛑 error handling (payload.error, mongoose validation)
38+
### Mutations got `error: ErrorInterface` field in theirs payload for better error handling
3739

38-
- Add `error` field & handler for mutations' payload #248
39-
- Resolvers createOne createMany now returns validation errors
40+
All mutation resolvers got `error` field in their payloads. And now clients may choose between two variants how they may receive a runtime resolver error if it happens.
41+
42+
1) First variant, as usual, via `errors` field in the response payload. Assume the following mutation produce runtime error:
43+
44+
```graphql
45+
mutation {
46+
userCreate(...) {
47+
recordId
48+
}
49+
}
50+
```
51+
52+
So you will receive such response from the GraphQL server:
53+
54+
```js
55+
{
56+
data: { userCreate: null },
57+
errors: [{
58+
message: 'E11000 duplicate key error collection: test.users index: email_1',
59+
extensions: { ... },
60+
path: ['userCreate'],
61+
}],
62+
}
63+
```
64+
65+
2) And the second new variant of obtaining errors is – the `error` field in mutation payload:
66+
67+
```graphql
68+
mutation {
69+
userCreate(...) {
70+
recordId
71+
error {
72+
message
73+
}
74+
}
75+
}
76+
```
77+
78+
In such case, you will get the error in `userCreate.error` field and the top-level `errors` field will be undefined:
79+
80+
```js
81+
{
82+
data: {
83+
userCreate: {
84+
error: {
85+
message: 'E11000 duplicate key error collection: test.users index: email_1',
86+
}
87+
}
88+
}
89+
}
90+
```
91+
92+
Moreover `userCreate.error` field is typed and may provide additional information for you. Let's take a look at the implementation of `error` field via SDL, which has some essential comments with technical explanations:
93+
94+
```graphql
95+
type UserCreatePayload {
96+
recordId: Int
97+
# First of all the `error` field is described by Interface
98+
error: ErrorInterface
99+
}
100+
101+
# Describing `UserCreatePayload.error` field by interface
102+
# provides the following advantages:
103+
# - you may return different types of errors with additional fields
104+
# - no matter what type of error is, you may request `message` field anyway
105+
interface ErrorInterface {
106+
message: String
107+
}
108+
109+
# For now in graphql-compose-mongoose exist 3 error types -
110+
# MongoError, ValidationError & RuntimeError
111+
112+
# MongoError is used if error was thrown from Database
113+
# and contains additional `code` field
114+
type MongoError implements ErrorInterface {
115+
message: String
116+
code: Int
117+
}
118+
119+
# ValidationError is used if error was thrown by Mongoose
120+
# when you create or update some documents.
121+
type ValidationError implements ErrorInterface {
122+
message: String
123+
errors: ValidatorError
124+
}
125+
126+
# RuntimeError is used as a fallback type if no one of the previous error was met.
127+
type RuntimeError implements ErrorInterface {
128+
message: String
129+
}
130+
```
131+
132+
So if clients need more details about mutation errors they able to write the following query:
133+
134+
```graphql
135+
mutation {
136+
userCreate(...) {
137+
recordId
138+
error {
139+
message
140+
__typename
141+
... on MongoError {
142+
code
143+
}
144+
... on ValidationError {
145+
errors {
146+
message
147+
path
148+
value
149+
}
150+
}
151+
}
152+
}
153+
}
154+
```
155+
156+
Quite long discussion about `error` implementation can be found in [issue #248](https://github.com/graphql-compose/graphql-compose-mongoose/issues/248)
157+
158+
### Added a new `ValidationError`
159+
160+
Resolvers `createOne`, `createMany`, `updateOne`, `updateById` now returns validator errors in the following shape:
161+
162+
```graphql
163+
type ValidationError implements ErrorInterface {
164+
message: String
165+
errors: ValidatorError
166+
}
167+
168+
type ValidatorError {
169+
message: String
170+
path: String
171+
value: JSON
172+
idx: Int!
173+
}
174+
```
175+
176+
So for such query:
177+
178+
```graphql
179+
mutation {
180+
createMany(
181+
records: [
182+
{ name: "Ok" },
183+
{ name: "John", someStrangeField: "Test" }
184+
]
185+
) {
186+
records {
187+
name
188+
}
189+
error {
190+
__typename
191+
message
192+
... on ValidationError {
193+
errors {
194+
message
195+
path
196+
value
197+
idx
198+
}
199+
}
200+
}
201+
}
202+
}
203+
```
204+
205+
You will receive the following response:
206+
207+
```js
208+
{
209+
data: {
210+
createMany: {
211+
records: null,
212+
error: {
213+
__typename: 'ValidationError',
214+
message: 'Nothing has been saved. Some documents contain validation errors',
215+
errors: [
216+
{
217+
message: 'this is a validate message',
218+
path: 'someStrangeField',
219+
value: 'Test',
220+
idx: 1, // <-- points that the second document has error
221+
},
222+
],
223+
},
224+
},
225+
},
226+
}
227+
```
228+
229+
[Issue #248](https://github.com/graphql-compose/graphql-compose-mongoose/issues/248)
40230

41231
## Improvements
42232

43233
### Now `_id` field can be of any type (Int, String, Object)
44234

45-
Before v9.0.0 was supported only `MongoID` type for `_id` field. Now it can be of any type – Int, String, Object. For using this feature you need to add `_id` field to mongoose schema with desired type and graphql-compose-mongoose will do the rest:
235+
Before v9.0.0 was supported only `MongoID` type for `_id` field. Now, it can be of any type – Int, String, Object. For using this feature, you need to add `_id` field to mongoose schema with the desired type, and graphql-compose-mongoose will do the rest:
46236

47237
```ts
48238
const BookSchema = new mongoose.Schema({
@@ -66,21 +256,95 @@ Notes:
66256

67257
[Issue #141](https://github.com/graphql-compose/graphql-compose-mongoose/issues/141)
68258

69-
### 🛑 recursive `filter._operators`
259+
### Add nested fields support, new operators `regex`, `exists` for `filter._operators`
260+
261+
Resolvers which have `filter` arg have `_operators` field, which allows you to write complex filtering logic with `AND`, `OR`, `gt`, `gte`, `lt`, `lte`, `ne`, `in`, `nin` operators. And in v9.0.0 were added `exists` & `regex`.
262+
Also were added support for nested fields like in `contacts.email` and `contacts.skype`:
263+
264+
```graphql
265+
query {
266+
findUsers(
267+
filter: {
268+
_operators: {
269+
age: { gt: 10, lt: 20 },
270+
address: { country: { in: ["US"] } },
271+
contacts: {
272+
email: { regex: "/3.COM/i" },
273+
skype: { exists: true },
274+
}
275+
}
276+
}
277+
) {
278+
_id
279+
name
280+
age
281+
}
282+
}
283+
```
70284

71-
- Adds support for recursive `filter._operators` (rename its type names ) #250
285+
By default, for performance reason, `graphql-compose-mongoose` generates operators *only for indexed* fields. BUT you may enable operators for all fields when creating resolver in the following way:
72286

73-
### 🛑 better alias & projection support for nested embedded documents
287+
```ts
288+
const userFindMany = UserTC.mongooseResolvers.findMany({
289+
filter: {
290+
// enables all operators for all fields
291+
operators: true,
292+
}
293+
)};
294+
```
74295
75-
- Nested projections for embedded documents #273
76-
- feat: nested aliases are now supported for `filter`, `projection` & `lean`
296+
OR provide more granular operators configuration for your needs:
77297
78-
### 🛑 typescript improvements for resolvers
298+
```ts
299+
const userFindMany2 = UserTC.mongooseResolvers.findMany({
300+
filter: {
301+
// more granular operators configuration
302+
operators: {
303+
// for `age` field add just 3 operators
304+
age: ['in', 'gt', 'lt'],
305+
// for non-indexed `amount` field add all operators
306+
amount: true,
307+
// don't add this field to operators
308+
indexedField: false,
309+
},
310+
},
311+
// add suffix for avoiding type names collision with resolver above
312+
suffix: 'AnotherFindMany',
313+
)};
314+
```
315+
316+
[Issue #250](https://github.com/graphql-compose/graphql-compose-mongoose/issues/250)
317+
318+
### Better alias support for nested embedded fields
79319
80-
- source is now typed, and first level of available args
320+
Mongoose support [aliases](https://mongoosejs.com/docs/guide.html#aliases) for fields. You may have short field names in DB `t`, `a` but they will be present in your models and graphql types under the full names – `title`, `author`:
321+
322+
```ts
323+
const BookSchema = new mongoose.Schema({
324+
_id: { type: Number },
325+
t: { type: String, alias: 'title' },
326+
a: { type: AuthorSchema, alias: 'author' },
327+
meta: {
328+
v: { type: Number, alias: 'votes' },
329+
f: { type: Number, alias: 'favs' },
330+
}
331+
});
332+
```
333+
334+
From the example above, you can notice that aliases can be used for embedded fields like `votes` & `favs`.
335+
336+
Moreover, `graphql-compose-mongoose` re-implements alias logic to make alias support in resolvers with `lean: true` option (when graphql get raw documents from the database).
337+
338+
[Issue #273](https://github.com/graphql-compose/graphql-compose-mongoose/issues/273)
81339
82340
## Performance improvements
83341
342+
### Added projection for nested embedded documents
343+
344+
Before v9.0.0, it was supported projection only for top-level fields. But now `graphql-compose-mongoose` support projection for embedded (nested) fields. It helps reduce data transfer between MongoDB and GraphQL server.
345+
346+
[Issue #273](https://github.com/graphql-compose/graphql-compose-mongoose/issues/273)
347+
84348
### Added new `dataLoader` & `dataLoaderMany` resolvers
85349
86350
These resolvers are helpful for relations construction between Entities for avoiding the N+1 Problem via [DataLoader](https://github.com/graphql/dataloader). This problem occurs when a client requests an array of records with some relation data:
@@ -192,6 +456,10 @@ From `UpdateByIdRecord` input type was extracted `_id` field on top level.
192456
193457
[Issue #257](https://github.com/graphql-compose/graphql-compose-mongoose/issues/257)
194458
459+
### `createMany` resolver now validates all records before save
460+
461+
Before 9.0.0 graphql-compose-mongoose may save some records provided to `createMany` even some other fail with a validation error. Now it firstly will check that all records are valid, and if some records contain errors, then no one document will be saved.
462+
195463
### Some generated types were renamed
196464
197465
- type for `filter._operators` field. Was `OperatorsXXXFilterInput` became `XXXFilterOperatorsInput`. It helps to keep all generated types with the same prefix for `XXX` entity.
@@ -202,6 +470,7 @@ From `UpdateByIdRecord` input type was extracted `_id` field on top level.
202470
- Refactor `pagination` & `connection` resolvers (now they are as dependencies) [#272](https://github.com/graphql-compose/graphql-compose-mongoose/issues/272)
203471
- Allow to provide `suffixes` for resolvers configs [#268](https://github.com/graphql-compose/graphql-compose-mongoose/issues/268)
204472
- Remove `getRecordIdFn()` [#262](https://github.com/graphql-compose/graphql-compose-mongoose/issues/262)
473+
- TypeScript definition improvements for resolvers: `source` is now typed, and first level of available `args` in resolvers
205474
206475
## Thanks
207476
@@ -210,7 +479,7 @@ From `UpdateByIdRecord` input type was extracted `_id` field on top level.
210479
It will not be possible to provide such great improvements in v9.0.0 without the following amazing peoples:
211480
212481
- [Robert Lowe](@RobertLowe) – new improved error payload for Mutations and better validation Errors on document creating/updating.
213-
- [Sean Campbell](natac13) – nested projection for reducing the amount of transmitted data from DB.
482+
- [Sean Campbell](@natac13) – nested projection for reducing the amount of transmitted data from DB.
214483
- [Morgan Touverey Quilling](@toverux) – non-nullability for fields with default values, help in lean resolvers.
215484
216485
Thank you very much for your help 🙏
@@ -222,7 +491,7 @@ Special thanks to our sponsors which joined recently:
222491
- **Bruce agency ($250)** – Investing in JAMstack, headless and touchless experiences since 2007, with over 250+ projects built. <https://bruce.agency/>
223492
- **Robert Lowe ($200)** – freelancer with great experience in Realtime web, mobile and desktop apps <http://robertlowe.ca>
224493
225-
And thanks a lot to regular backers – [ScrapeHero](https://www.scrapehero.com/marketplace/) $5,[Woorke](https://woorke.com) $2, [420 Coupon Codes](https://420couponcodes.com/) $2,[ScrapingBee](https://www.scrapingbee.com/) $2, [Adapt.js](https://adaptjs.org/) $2.
494+
And thanks a lot to regular backers – [ScrapeHero](https://www.scrapehero.com/marketplace/) $5, [Woorke](https://woorke.com) $2, [420 Coupon Codes](https://420couponcodes.com/) $2,[ScrapingBee](https://www.scrapingbee.com/) $2, [Adapt.js](https://adaptjs.org/) $2.
226495
227496
Your donations inspire me to improve `graphql-compose` packages. And allow to spend more time on it. Thank you very much for your support!
228497

0 commit comments

Comments
 (0)