UNPKG

7.26 kBMarkdownView Raw
1# TypeScript MongoDB Typings
2
3## Overview
4
5This package generates TypeScript types for MongoDB server-side developers.
6
7It uses GraphQL directives to declare the types you want to generate and use in your MongoDB.
8
9It take a declaration like this:
10
11```graphql
12type User @entity {
13 id: String @id
14 username: String! @column
15 email: @column
16}
17```
18
19And generates a TypeScript interface like this:
20
21```typescript
22import { ObjectID } from 'mongodb';
23
24export interface UserDbObject {
25 _id: ObjectID;
26 username: string;
27 email?: string | null;
28}
29```
30
31So you can use it when you read/write to your database, and expect a specific structure.
32
33## How to use?
34
35To use this package, install is using Yarn into your project, as a dependency:
36
37```
38yarn add graphql-codegen-typescript-mongodb-template
39```
40
41Then, you need to add the directives declaration to your GraphQL Schema definition:
42
43```typescript
44import { makeExecutableSchema } from 'graphql-tools';
45import { DIRECTIVES } from 'graphql-codegen-typescript-mongodb-template';
46
47const schema = makeExecutableSchema({
48 typeDefs: [
49 DIRECTIVES
50 // the rest of your GraphQL types
51 ],
52 resolvers
53});
54```
55
56Now, use this template with the GraphQL code generator:
57
58```
59gql-gen --template graphql-codegen-typescript-mongodb-template --schema ./src/my-schema.js
60```
61
62> IMPORTANT: Because of GraphQL behavior, you have to use --schema and provide a JavaScript export, otherwise you will lose your GraphQL Directives usage
63
64Now, add the directives to your GraphQL definitions, and generate your MongoDB models file.
65
66## Directives
67
68### `@entity(embedded: Boolean, additionalFields: [AdditionalEntityFields])` (on `OBJECT`)
69
70Use this directive to declare that a specific GraphQL type should have a generated MongoDB models.
71
72- `embedded: Boolean` - specify this to declare that this entity turns into an object inside another entity. For example, if you want your structure to be `{ _id: string, username: string, profile: { name: string }}`, then your GraphQL type `Profile` should be an embedded type.
73- `additionalFields: [AdditionalEntityFields]` - specify any additional fields that you with to add to your MongoDB object, and are not part of your public GraphQL schema.
74
75```graphql
76type User @entity(additionalFields: [
77 { path: "services.login.token", type: "string" }
78]) {
79 id: String @id
80 email: @column
81}
82```
83
84### `@column(name: string, overrideType: String, overrideIsArray: Boolean)` (on `FIELD_DEFINITION`)
85
86Use this directive to declare that a specific GraphQL field should be part of your generated MongoDB type.
87
88- `overrideType: String` - use this to override the type of the field, for example, if you persist dates as `Date` but expose them as `String`.
89- `overrideIsArray: Boolean` - specify `true`/`false` to override the generated result and force it to generate an array type (or not).
90- `name: String` - you can specify the name of the field as you wish to have it on your DB - it could be also a path (`a.b.c`). This is a shortcut for `@map` directive.
91
92> Note that if your property is an embedded entity, you should use `@embedded` instead.
93
94### `@id` (on `FIELD_DEFINITION`)
95
96Use this directive on your field that turns into your MongoDB `_id`. Usually it's your `id` field of the GraphQL `type`.
97
98### `@link` (on `FIELD_DEFINITION`)
99
100Use this directive to declare that a specific field is a link to another type in another table. This will use the `ObjectID` type in your generated result.
101
102### `@embedded` (on `FIELD_DEFINITION`)
103
104Use this directive to declare that a specific field is integrated into the parent entity, and should be an object inside it.
105
106### `@map(path: String)` (on `FIELD_DEFINITION`)
107
108Use this directive to override the `path` or the name of the field. It's useful for creating a more complex object structure on the database.
109
110For example, if you wish to expose a field as `username` on your schema, but persist it in `credentials.username` on your DB.
111
112You can either specify the name of the field, or a `path` to it to generate an object.
113
114```graphql
115type User @entity {
116 username: String @column @map(path: "credentials.username")
117}
118```
119
120Will output:
121
122```typescript
123export interface UserDbObject {
124 credentials: {
125 username: string;
126 };
127}
128```
129
130### `@abstractEntity(discriminatorField: String!)` (on `INTERFACE`)
131
132Use this directive on your GraphQL `interface`s to indicate that this interface is a common base for other database types.
133
134Specify `discriminatorField` to tell the generator what is the name of the field you are using on your database to identify how which object is implementing the interface.
135
136For example:
137
138```graphql
139interface BaseNotification @abstractEntity(discriminatorField: "notificationType") {
140 id: ID! @id
141 createdAt: String! @column(overrideType: "Date")
142}
143
144type TextNotification implements BaseNotification @entity {
145 id: ID!
146 createdAt: String!
147 content: String! @column
148}
149```
150
151This way, you will get:
152
153```typescript
154export interface BaseNotificationDbInterface {
155 notificationType: string;
156 _id: ObjectID;
157 createdAt: Date;
158}
159
160export interface TextNotificationDbObject extends BaseNotificationDbInterface {
161 content: string;
162}
163```
164
165### `@union(discriminatorField: String)` (on `UNION`)
166
167This directive is similar to `@abstractEntity`, but for unions (that not necessarily have common fields).
168
169Specify `discriminatorField` to tell the generator what is the name of the field you are using on your database to identify how which object is implementing the interface.
170
171```graphql
172type A @entity {
173 fieldA: String @column
174}
175
176type B @entity {
177 fieldB: String @column
178}
179
180union PossibleType = A | B @union(discriminatorField: "entityType")
181```
182
183You will get:
184
185```typescript
186export interface ADbObject {
187 fieldA: string;
188}
189
190export interface BDbObject {
191 fieldB: string;
192}
193
194export type PossibleType = { entityType: string } & (ADbObject | BDbObject);
195```
196
197## Simple Example
198
199For example, if you have a `User` (that matches to `users` table), `Profile` (which is part of your `User`) and `Friends` which is an array of `ObjectID` inside your user, use the following schema:
200
201```
202type User @entity {
203 id: String! @id
204 username: String! @column
205 email: String! @column
206 profile: Profile! @embedded
207 friendsCount: Int! # this field won't get a generated MongoDB field
208 friends: [User]! @link
209}
210
211type Profile @entity(embedded: true) {
212 name: String! @column
213 age: Int! @column
214}
215```
216
217The output will be:
218
219```typescript
220import { ObjectID } from 'mongodb';
221
222export interface UserDbObject {
223 _id: ObjectID;
224 username: string;
225 email: string;
226 profile: ProfileDbObject;
227 friends: ObjectID[];
228}
229
230export interface ProfileDbObject {
231 name: string;
232 age: string;
233}
234```
235
236## Generator Config
237
238This generator supports custom config and output behavior. Use to following flags/environment variables to modify your output as you wish:
239
240### `schemaNamespace` (or `CODEGEN_SCHEMA_NAMESPACE`, default value: `null`)
241
242This will cause the codegen to wrap the generated schema typings with a TypeScript namespace.
243
244Use this feature if you need to run the codegen on multiple schemas, but getting a unified types (read more [here](https://www.typescriptlang.org/docs/handbook/declaration-merging.html))